Copying my post from https://github.com/rust-lang/rust/issues/49792#issuecomment-379638786:
Two recent internals threads with thoughts around this area:
It seems to me like there’s a general common theme here of “safe, but a bit weird and rather transmute-y” conversions: this thread’s uN <=> [u8; N/8], the first thread’s u16x8 <=> u32x4 and u32 <=> f32, some parts of as like u32 <=> i32 that currently don’t have a method version, and extended versions of that like &'a u32 <=> &'a i32 that are never exposed as safe today (but could be).
So here’s a sketch of an idea using #[marker] traits:
#[marker] unsafe trait InplaceReinterpretAs<T> {}
unsafe impl<T> InplaceReinterpretAs<T> for T {}
unsafe impl InplaceReinterpretAs<[u8; 4]> for u32 {}
unsafe impl InplaceReinterpretAs<i32> for u32 {}
unsafe impl InplaceReinterpretAs<u32> for i32 {}
unsafe impl<T, U> InplaceReinterpretAs<*const U> for *const T {}
unsafe impl<T, U> InplaceReinterpretAs<*mut U> for *mut T {}
unsafe impl InplaceReinterpretAs<u16x8> for u32x4 {}
unsafe impl InplaceReinterpretAs<u32x4> for u16x8 {}
#[marker] unsafe trait ReinterpretAs<T> {
// Because it's a marker trait, these cannot be overridden,
// and thus their behaviour is always predicatable
fn reinterpret(self) -> T {
unsafe {
let r = ptr::read_unaligned(&self as *const Self as *const T);
mem::forget(self);
r
}
}
unsafe fn reinterpret_unchecked(x: T) -> Self {
let r = ptr::read_unaligned(&x as *const T as *const Self);
mem::forget(x);
r
}
}
unsafe impl<T, U> ReinterpretAs<U> for T where T: InplaceReinterpretAs<U> {}
unsafe impl<'a, T, U> ReinterpretAs<&'a U> for &'a T where T: InplaceReinterpretAs<U> {}
unsafe impl<'a, T, U> ReinterpretAs<&'a mut U> for &'a mut T where T: InplaceReinterpretAs<U> {}
unsafe impl ReinterpretAs<u32> for [u8;4] {} // not ok in-place, but fine as memcpy
Certainly std is generally adverse to introducing these using traits, but I think the recursiveness of the scenario makes the trait version more compelling than normal in this case. If one can turn a u32 into a [u8; 4] safely, why not also be able to turn a &[u32] into a &[[u8; 4]] safely?
(Name inspired by C++'s reinterpret_cast, obviously.)