Advertisements
I want to design a trait with a mutable and an immutable getter to some field of self
.
However, I want that the implementer of the trait has to implement only one method, typically the mutable getter.
I have found this solution (playground):
pub trait MyTrait<T> {
fn inside_mut(&mut self) -> &mut T;
fn inside_ref(&self) -> &T {
let ptr = self as *const Self as *mut Self;
&* unsafe { &mut *ptr }.inside_mut()
}
}
pub struct Data(String);
impl MyTrait<String> for Data {
fn inside_mut(&mut self) -> &mut String { &mut self.0 }
}
fn main() {
let mut data = Data(format!("Foo"));
let x: &String = data.inside_ref();
let y: &String = data.inside_ref();
println!("x -> {x}");
println!("y -> {y}");
*data.inside_mut() = format!("Bar");
println!("data.0 -> {}", data.0);
}
Result:
Standard Error
Compiling playground v0.0.1 (/playground)
Finished release [optimized] target(s) in 0.93s
Running `target/release/playground`
Standard Output
x -> Foo
y -> Foo
data.0 -> Bar
My question: is this approach sound?
>Solution :
No, this is not sound.
The user could modify self
in his implementation of inside_mut
, which would also modify the struct in inside_ref
.
Like this:
pub trait MyTrait<T> {
fn inside_mut(&mut self) -> &mut T;
fn inside_ref(&self) -> &T {
let ptr = self as *const Self as *mut Self;
&*unsafe { (&mut *ptr).inside_mut() }
}
}
#[derive(Debug)]
struct MyStruct {
value: i32,
}
impl MyTrait<i32> for MyStruct {
fn inside_mut(&mut self) -> &mut i32 {
self.value += 1;
&mut self.value
}
}
fn main() {
// Important: this is not `mut`!!!
let x = MyStruct { value: 42 };
println!("{:?}", x);
x.inside_ref();
println!("{:?}", x);
}
MyStruct { value: 42 }
MyStruct { value: 43 }
That means that this implementation is unsound:
Behavior considered undefined
- Mutating immutable data. All data inside a
const
item is immutable. Moreover, all data reached through a shared reference or data owned by an immutable binding is immutable, unless that data is contained within anUnsafeCell<U>
.