Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate transmutation size using const code #239

Open
joshlf opened this issue Aug 9, 2023 · 0 comments
Open

Validate transmutation size using const code #239

joshlf opened this issue Aug 9, 2023 · 0 comments
Labels
compatibility-breaking Changes that are (likely to be) breaking

Comments

@joshlf
Copy link
Member

joshlf commented Aug 9, 2023

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 not cargo check rust-lang/rust#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

#![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> {}
@joshlf joshlf added the compatibility-breaking Changes that are (likely to be) breaking label Aug 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compatibility-breaking Changes that are (likely to be) breaking
Projects
None yet
Development

No branches or pull requests

1 participant