Validate transmutation size using `const` code
- Dominant language
- Rust
- Stars
- 2.6k
- Forks
- 179
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 29
Description
As discussed [here](https://github.com/google/zerocopy/issues/159#issue-1588293938) and [here](https://github.com/google/zerocopy/pull/183#discussion_r1208678157), 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 https://github.com/rust-lang/rust/issues/112301, code that generates errors when compiled with `cargo build` would not generate errors when compiled with `cargo 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](https://github.com/rust-lang/rust/issues/92827)
```rust
#![feature(associated_const_equality)]
unsafe trait MaybeTransmutableFrom {
const IS_TRANSMUTABLE: bool;
}
unsafe impl MaybeTransmutableFrom for U {
const IS_TRANSMUTABLE: bool = {
assert!(core::mem::size_of::() == core::mem::size_of::());
true
};
}
unsafe trait TransmutableFrom {}
unsafe impl TransmutableFrom for U where U: MaybeTransmutableFrom {}
```
## [generic_const_exprs](https://github.com/rust-lang/rust/issues/76560)
```rust
#![feature(generic_const_exprs)]
unsafe trait MaybeTransmutableFrom {
const IS_TRANSMUTABLE: bool;
}
unsafe impl MaybeTransmutableFrom for U {
const IS_TRANSMUTABLE: bool = {
assert!(core::mem::size_of::() == core::mem::size_of::());
true
};
}
unsafe trait TransmutableFrom {}
unsafe impl TransmutableFrom for U
where
U: MaybeTransmutableFrom,
(): Bool<{ U::IS_TRANSMUTABLE }>,
{
}
trait Bool {}
impl Bool for () {}
```
Alternatively:
```rust
#![feature(generic_const_exprs)]
unsafe trait MaybeTransmutableFrom {}
unsafe impl
MaybeTransmutableFrom<{ core::mem::size_of::() == core::mem::size_of::() }, T> for U
{
}
unsafe trait TransmutableFrom {}
unsafe impl TransmutableFrom for U where U: MaybeTransmutableFrom {}
```
Contributor guide
Assessment
This issue has not been assessed yet.