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

Write generic transmute #4

Open
joshlf opened this issue Sep 19, 2022 · 1 comment
Open

Write generic transmute #4

joshlf opened this issue Sep 19, 2022 · 1 comment

Comments

@joshlf
Copy link
Member

joshlf commented Sep 19, 2022

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
@InternetOfTofu
Copy link

InternetOfTofu commented Feb 16, 2023

We (crosvm) are looking at using zerocopy crate's FromBytes and AsBytes to replace DataInit (our legacy creation similar to pod, requires manually marking types using unsafe impl DataInit for xxx {}).

We have made major progress on it (crrev.com/c/4237765) but for instances like https://chromium.googlesource.com/crosvm/crosvm/+/HEAD/devices/src/usb/xhci/xhci_abi.rs#683 it seems hard to use zerocopy's current safe transmute macro to implement.

@joshlf joshlf mentioned this issue Aug 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants