Write generic transmute
- Dominant language
- Rust
- Stars
- 2.6k
- Forks
- 179
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 29
Description
*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](https://fuchsia-review.googlesource.com/c/fuchsia/+/569463/comments/764fec61_c62f688d) (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: FromBytes + Sized {}
> ```
>
> that your derive macros generate, and then implement your transmute function as
>
> ```
> fn transmute(x: T)
> where
> T: AsBytesSized,
> U: FromBytesSized,
> {
> 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` 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` 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` 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:
```rust
impl Size<0> for [T; 0] {} // OK
impl, const N: usize> Size for [T; 1] {} // OK
impl, const N: usize> Size<{ N * 2 }> for [T; 2] {} // Illegal
```
Contributor guide
Assessment
This issue has not been assessed yet.