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

Support operations on byte arrays #248

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

Support operations on byte arrays #248

joshlf opened this issue Aug 10, 2023 · 0 comments
Labels
blocked-on-generic_const_exprs https://github.com/rust-lang/rust/issues/76560 blocked-on-rust Blocked on a Rust feature landing or stabilizing compatibility-nonbreaking Changes that are (likely to be) non-breaking

Comments

@joshlf
Copy link
Member

joshlf commented Aug 10, 2023

We want to be able to support operations on byte arrays, especially [u8; size_of::<T>()] for some zerocopy-compatible type T. E.g.:

trait FromBytes {
    fn from_bytes(bytes: [u8; size_of::<Self>()]) -> Self
        where Self: Sized;
    fn ref_from_bytes(bytes: &[u8; size_of::<Self>()]) -> Self
        where Self: Sized + Unaligned;
}

trait AsBytes {
    fn into_bytes(self) -> [u8; size_of::<Self>()]
        where Self: Sized;
    fn as_bytes(&self) -> &[u8; size_of::<Self>()]
        where Self: Sized;
}

Stabilize size_of::<T>()

One approach we could take to accomplish this would be to stabilize size_of::<T>() for use in a type in a generic context (a special case of generic_const_exprs.

Polyfill

Another approach - that we can implement on our own without being blocked on Rust - is to add a polyfill type like the following

/// An array of `size_of::<T>()` bytes.
///
/// Since the `generic_const_exprs` feature is unstable, it is not possible
/// to use the type `[u8; size_of::<T>()]` in a context in which `T` is
/// generic. `ByteArray<T>` fills this gap.
///
/// # Layout
///
/// `ByteArray<T>` has the same layout and bit validity as `[u8; size_of::<T>()]`.
#[derive(FromBytes, Unaligned)]
#[repr(transparent)]
pub struct ByteArray<T: NoCell>(
    // INVARIANT: All of the bytes of this field are initialized.
    Unalign<MaybeUninit<T>>,
);

Note the T: NoCell bound; this is required because MaybeUnint doesn't "disable" UnsafeCell, and so it would be unsound to produce a &[u8; N] and a &ByteArray<T> to the same memory if T contained an UnsafeCell.

If we use a type which supports unsized types (Unalign doesn't), we could even make this more powerful than [u8; size_of::<T>()]. For T: Sized, ByteArray<T> would have the same layout as T, but for T: !Sized, it would have a layout closer to [u8]. It's unclear how an unsized version of this could be constructed, though, since the fat pointer would need to know the number of trailing slice elements in T, not the number of bytes.

This was originally prototyped (though never merged) here.

TODO: Is it possible to support T: ?Sized? MaybeUninit<T> requires T: Sized, and in general, unions don't support unsized types, so it's not possible to just manually implement a standin MaybeUninit that does support T: ?Sized.

@joshlf joshlf added the compatibility-nonbreaking Changes that are (likely to be) non-breaking label Aug 12, 2023
@joshlf joshlf changed the title Add byte array (polyfill for [u8; size_of::<T>()]) Support operations on byte arrays Sep 18, 2023
@joshlf joshlf added blocked-on-rust Blocked on a Rust feature landing or stabilizing blocked-on-generic_const_exprs https://github.com/rust-lang/rust/issues/76560 labels Sep 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocked-on-generic_const_exprs https://github.com/rust-lang/rust/issues/76560 blocked-on-rust Blocked on a Rust feature landing or stabilizing compatibility-nonbreaking Changes that are (likely to be) non-breaking
Projects
None yet
Development

No branches or pull requests

1 participant