Open
Description
As discussed here and here, it would be great if we could replace transmute!
with an equivalent transmute
function that performs size verification using const
code. This would simplify the implementation, and would allow transmute
to be used in type-generic contexts (transmute!
can only be called in a context in which all types are concrete). However, due to limitations with const generics, errors can only be reported at monomorphization time. This causes some problems:
- There's no way to "bubble up" the size equality requirement since it's not actually expressed in the type system
- Type-generic APIs will never fail - they can only fail when they are used in a concrete context; this is true even across crate boundaries, meaning that it would be easy to accidentally publish a buggy API
- Thanks to Const evaluation can fail during
cargo build
but notcargo check
rust-lang/rust#112301, code that generates errors when compiled withcargo build
would not generate errors when compiled withcargo check
There are a few ways that we could lift this information into the type system and avoid these issues, but all of them rely on unstable features:
associated_const_equality
#![feature(associated_const_equality)]
unsafe trait MaybeTransmutableFrom<T> {
const IS_TRANSMUTABLE: bool;
}
unsafe impl<T, U> MaybeTransmutableFrom<T> for U {
const IS_TRANSMUTABLE: bool = {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<U>());
true
};
}
unsafe trait TransmutableFrom<T> {}
unsafe impl<T, U> TransmutableFrom<T> for U where U: MaybeTransmutableFrom<T, IS_TRANSMUTABLE = true> {}
generic_const_exprs
#![feature(generic_const_exprs)]
unsafe trait MaybeTransmutableFrom<T> {
const IS_TRANSMUTABLE: bool;
}
unsafe impl<T, U> MaybeTransmutableFrom<T> for U {
const IS_TRANSMUTABLE: bool = {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<U>());
true
};
}
unsafe trait TransmutableFrom<T> {}
unsafe impl<T, U> TransmutableFrom<T> for U
where
U: MaybeTransmutableFrom<T>,
(): Bool<{ U::IS_TRANSMUTABLE }>,
{
}
trait Bool<const BOOL: bool> {}
impl Bool<true> for () {}
Alternatively:
#![feature(generic_const_exprs)]
unsafe trait MaybeTransmutableFrom<const IS_TRANSMUTABLE: bool, T> {}
unsafe impl<T, U>
MaybeTransmutableFrom<{ core::mem::size_of::<T>() == core::mem::size_of::<U>() }, T> for U
{
}
unsafe trait TransmutableFrom<T> {}
unsafe impl<T, U> TransmutableFrom<T> for U where U: MaybeTransmutableFrom<true, T> {}