Skip to content

Validate transmutation size using const code #239

Open
@joshlf

Description

@joshlf

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> {}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions