I have struct that has unsafe code and raw mutable pointers to another type of struct. The unsafe struct should only be used during the lifetime of the other struct but you can not specify a lifetime for pointers. I discovered std::marker::PhantomData
could be used for this unused lifetime issues but I am having issues getting it to work. I'm not sure if this is an invalid use case or I'm doing something wrong.
use std::marker::PhantomData;
pub struct Test {
value: u32,
}
impl Test {
pub fn value(&self) {
println!("{}", self.value)
}
pub fn set_value(&mut self, value: u32) {
self.value = value;
}
}
// I want compiler to complain about the lifetime of test
// so that UnsafeStruct is not used after test is dropped
pub struct UnsafeStruct<'a> {
test: *mut Test,
phantom: PhantomData<&'a mut Test>,
}
impl<'a> UnsafeStruct<'a> {
pub fn new(test: &'a mut Test) -> UnsafeStruct<'a> {
UnsafeStruct {
test: test,
phantom: PhantomData,
}
}
pub fn test_value(&self) {
unsafe { println!("{}", (*self.test).value) }
}
pub fn set_test_value(&mut self, value: u32) {
unsafe {
(*self.test).set_value(value);
}
}
}
fn main() {
// No borrow checker errors
// but the compiler does not complain about lifetime of test
let mut unsafe_struct: UnsafeStruct;
{
let mut test = Test { value: 0 };
unsafe_struct = UnsafeStruct {
test: &mut test,
phantom: PhantomData,
};
unsafe_struct.set_test_value(1);
test.value();
test.set_value(2);
unsafe_struct.test_value();
}
unsafe_struct.set_test_value(3);
unsafe_struct.test_value();
// Lifetime errors caught
// but there will be borrow checker errors if you fix
let mut unsafe_struct: UnsafeStruct;
{
let mut test = Test { value: 0 };
unsafe_struct = UnsafeStruct::new(&mut test);
unsafe_struct.set_test_value(1);
test.value();
test.set_value(2);
unsafe_struct.test_value();
}
unsafe_struct.set_test_value(3);
unsafe_struct.test_value();
// Borrow checker errors when you fix lifetime error
{
let mut test = Test { value: 0 };
let mut unsafe_struct: UnsafeStruct;
unsafe_struct = UnsafeStruct::new(&mut test);
unsafe_struct.set_test_value(1);
test.value();
test.set_value(2);
unsafe_struct.test_value();
}
}
If I create the UnsafeStruct
directly the compiler does not catch the lifetime errors and I would like to use a constructor function anyway. If I use the constructor function then I have borrow checker errors. Is it possible to fix this code, such that the compiler will error when attempting to use a UnsafeStruct
outside of the lifetime of the corresponding Test
, but will not have the borrow checking errors shown in the example?