I have some struct, something like this:
struct MyStruct<T> {
field1: T,
field2: T,
field3: T,
}
What I know and really sure about the struct:
- All the fields have the same type;
- All the fields are
Sized; - Exact number of fields for every
struct(3in this example);
In my project it might be useful to access structs like this like a slices. So what I've done:
impl<T> AsRef<[T]> for MyStruct<T> {
fn as_ref(&self) -> &[T] {
let ptr = self as *const Self;
let ptr2 = ptr as *const T;
unsafe { std::slice::from_raw_parts(ptr2, 3) }
}
}
Now I can access fields of MyStruct like this:
let s = MyStruct { field1: 1.0, field2: 2.0, field3: 3.0 };
s.as_ref()[1]
I've tested some examples both in dev and release modes and didn't find any errors. Still I'm not sure about this kind of pointer magic.
Rust cannot guarantee that memory layout will preserve an order of the fields. On the other hand, as far as I know, it happens only when struct has fields with different sizes and need to be aligned.
So I'm really curious:
- Are there any rust safe guarantee violations?
- Is there any safe or performance difference between this variant and the next one?
- Should I use a
unioninstead of this trick?
impl<T> AsRef<[T]> for MyStruct<T> {
fn as_ref(&self) -> &[T] {
let tmp: &[T; 3] = unsafe { std::mem::transmute(self) };
tmp.as_ref()
}
}