Skip to content

Write generic transmute #4

@joshlf

Description

@joshlf

Migrated from https://fxbug.dev/82795

See also: #1316.

The zerocopy transmute! macro can only be called in a context in which both the input and output types are concrete. As suggested in this comment (reproduced below), it should be possible to make a transmute function which can operate on generic types. This would require a substantial increase to zerocopy's API surface, and more code in zerocopy-derive, so it should only be done if a use case arises.

Copy of the comment:

One way you could get rid of this is by adding a

unsafe trait FromByteSized<const SIZE: usize>: FromBytes + Sized {}

that your derive macros generate, and then implement your transmute function as

fn transmute<T, U, const N: usize>(x: T)
where
  T: AsBytesSized<N>,
  U: FromBytesSized<N>,
{
  let eyepatch = ManuallyDrop::new(x);
  unsafe { mem::transmute_copy(&*eyepatch) }
}

If no type parameters are provided, Rust will correctly infer this, although you cannot yet write something like transmute::<_, U, _>(). This behavior isn't any better than the macro, but it makes it a Real Function at least. It is unclear to what degree this can be made to work in a generic context... probably propagating those bounds and the extra const parameter is "enough".

In the future, you could have AsBytesSized<N> provide an into_bytes() function that produces an unaligned [u8; N].

See: https://godbolt.org/z/vnbx9Y843

I took a quick stab at implementing a prototype of this (using a separate Size<const N: usize> trait), and ran into a few problems:

  • While it technically supports generics, if one of the types is concrete and the other is generic, the generic type must have a bound of the form Size<N> where N is a compile-time constant. You'd end up with a bound like T: FromBytes + Size<60>. Not the end of the world, but kind of ugly.
  • I can't figure out how to implement Size for arrays. There's no way to perform multiplication in a const generic context, so the following is illegal:
    impl<T> Size<0> for [T; 0] {}                                  // OK
    impl<T: Size<N>, const N: usize> Size<N> for [T; 1] {}         // OK
    impl<T: Size<N>, const N: usize> Size<{ N * 2 }> for [T; 2] {} // Illegal

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions