I like the idea, but I don’t think we could later introduce language support in a backcompat way if we make the trait unsafe, since all unsafe impl Mappable for MyType {} incantations would become incorrect when we did that. I think we could use the following trick however:
#[unstable]
pub trait EnableMappable {}
impl EnableMappable for u8, u16, u32, u64, i8, i16, i32, i64, f32, f64 {}
impl<T: EnableMappable> EnableMappable for [T] {}
pub trait Mappable: EnableMappable {}
impl<T: EnableMappable> Mappable for T {}
This allows users of std to bound types with Mappable since it is stable, but prevent them from writing their own impl-s since they’d need to implement EnableMappable which is unstable.
Then when language support comes in some form or another, we can get rid of the EnableMappable trait altogether. What do you think?
Regarding transmute_mappable_ref, I’ll admit I don’t know too much about LLVM internals, but my understanding is that the optimizer is allowed to assume that pointer of different types never alias. UnsafeCell wouldn’t help at all in this case since that only deals with pointers of the same type; I’m sure LLVM still assumes UnsafeCell<f32> and UnsafeCell<u32> never alias.
This is very useful in C++ where pointers, unless defined as restrict, are otherwise always considered aliasable. Due to Rust’s limits on mutability and aliasing, I think this is actually a non-issue: if I had a two pointers of different types pointing to the same underlying piece of memory, neither of them could modify it so LLVM may as well think they don’t alias.
I mention this in my pre-RFC and suggest being conservative initially. We can relax -> &[u8] to -> &D later (assuming the defaults-affect-inference changes land).
I’d really like someone’s input with more LLVM knowledge.
Reading private fields with map_bytes makes me queasy, but I take your point—mem::forget also makes me queasy. However, reading from padding still applies, so in both transmute_mappable and map_bytes the source needs to be at least ReprPacked.