struct Wrapper1(u32);
impl Wrapper1 {
fn inner(&self) -> &u32 {
&self.0
}
}
struct Wrapper2(u32);
struct Wrapper3(Wrapper1);
trait GetInner {
fn inner(&self) -> &Wrapper2;
}
impl GetInner for Wrapper3 {
fn inner(&self) -> &Wrapper2 {
let raw_pointer = self.0.inner() as *const u32 as *const Wrapper2;
unsafe { &*raw_pointer }
}
}
I have this snippet of code showcasing a simplification of my problem.
I have to rely on unsafe
because I cannot just do this:
impl GetInner for Wrapper3 {
fn inner(&self) -> &Wrapper2
&Wrapper2(*self.0.inner())
}
}
Is it sound? Somebody in my team raised concern about alignment.
Somebody else mention we have to use #[repr(transparent)]
on the wrappers types in order to make it more safe.
You need
Wrapper2
to be#[repr(transparent)]
or#[repr(C)]
. Layout of#[repr(Rust)
structs is not guaranteed.However, if you do that, you don't need unsafe anymore - you can use
bytemuck
: