Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/byteorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,11 +276,14 @@ example of how it can be used for parsing UDP packets.
[`AsBytes`]: crate::AsBytes
[`Unaligned`]: crate::Unaligned"),
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(any(feature = "derive", test), derive(FromZeroes, FromBytes, AsBytes, Unaligned))]
#[cfg_attr(any(feature = "derive", test), derive(KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned))]
#[repr(transparent)]
pub struct $name<O>([u8; $bytes], PhantomData<O>);
}

#[cfg(not(any(feature = "derive", test)))]
impl_known_layout!(O => $name<O>);

safety_comment! {
/// SAFETY:
/// `$name<O>` is `repr(transparent)`, and so it has the same layout
Expand Down
149 changes: 82 additions & 67 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,9 @@ impl DstLayout {
/// # Safety
///
/// Unsafe code may assume that `DstLayout` is the correct layout for `T`.
const fn for_type<T>() -> DstLayout {
#[doc(hidden)]
#[inline]
pub const fn for_type<T>() -> DstLayout {
// SAFETY: `align` is correct by construction. `T: Sized`, and so it is
// sound to initialize `size_info` to `SizeInfo::Sized { size }`; the
// `size` field is also correct by construction.
Expand Down Expand Up @@ -643,7 +645,16 @@ impl DstLayout {
///
/// This trait does not convey any safety guarantees to code outside this crate.
#[doc(hidden)] // TODO: Remove this once KnownLayout is used by other APIs
pub unsafe trait KnownLayout: sealed::KnownLayoutSealed {
pub unsafe trait KnownLayout {
// The `Self: Sized` bound makes it so that `KnownLayout` can still be
// object safe. It's not currently object safe thanks to `const LAYOUT`, and
// it likely won't be in the future, but there's no reason not to be
// forwards-compatible with object safety.
#[doc(hidden)]
fn only_derive_is_allowed_to_implement_this_trait()
where
Self: Sized;

#[doc(hidden)]
const LAYOUT: DstLayout;

Expand All @@ -654,9 +665,14 @@ pub unsafe trait KnownLayout: sealed::KnownLayoutSealed {
fn raw_from_ptr_len(bytes: NonNull<u8>, elems: usize) -> NonNull<Self>;
}

impl<T: KnownLayout> sealed::KnownLayoutSealed for [T] {}
// SAFETY: Delegates safety to `DstLayout::for_slice`.
unsafe impl<T: KnownLayout> KnownLayout for [T] {
#[allow(clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait()
where
Self: Sized,
{
}
const LAYOUT: DstLayout = DstLayout::for_slice::<T>();

// SAFETY: `.cast` preserves address and provenance. The returned pointer
Expand Down Expand Up @@ -3134,7 +3150,6 @@ where

mod sealed {
pub trait ByteSliceSealed {}
pub trait KnownLayoutSealed {}
}

// ByteSlice and ByteSliceMut abstract over [u8] references (&[u8], &mut [u8],
Expand Down Expand Up @@ -5023,78 +5038,78 @@ mod tests {
};
}

assert_impls!((): FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(u8: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(i8: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(u16: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(i16: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(u32: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(i32: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(u64: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(i64: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(u128: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(i128: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(usize: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(isize: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(f32: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(f64: FromZeroes, FromBytes, AsBytes, !Unaligned);

assert_impls!(bool: FromZeroes, AsBytes, Unaligned, !FromBytes);
assert_impls!(char: FromZeroes, AsBytes, !FromBytes, !Unaligned);
assert_impls!(str: FromZeroes, AsBytes, Unaligned, !FromBytes);

assert_impls!(NonZeroU8: AsBytes, Unaligned, !FromZeroes, !FromBytes);
assert_impls!(NonZeroI8: AsBytes, Unaligned, !FromZeroes, !FromBytes);
assert_impls!(NonZeroU16: AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroI16: AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroU32: AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroI32: AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroU64: AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroI64: AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroU128: AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroI128: AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroUsize: AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroIsize: AsBytes, !FromZeroes, !FromBytes, !Unaligned);

assert_impls!(Option<NonZeroU8>: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(Option<NonZeroI8>: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(Option<NonZeroU16>: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroI16>: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroU32>: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroI32>: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroU64>: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroI64>: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroU128>: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroI128>: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroUsize>: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroIsize>: FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!((): KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(u8: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(i8: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(u16: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(i16: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(u32: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(i32: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(u64: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(i64: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(u128: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(i128: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(usize: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(isize: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(f32: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(f64: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);

assert_impls!(bool: KnownLayout, FromZeroes, AsBytes, Unaligned, !FromBytes);
assert_impls!(char: KnownLayout, FromZeroes, AsBytes, !FromBytes, !Unaligned);
assert_impls!(str: KnownLayout, FromZeroes, AsBytes, Unaligned, !FromBytes);

assert_impls!(NonZeroU8: KnownLayout, AsBytes, Unaligned, !FromZeroes, !FromBytes);
assert_impls!(NonZeroI8: KnownLayout, AsBytes, Unaligned, !FromZeroes, !FromBytes);
assert_impls!(NonZeroU16: KnownLayout, AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroI16: KnownLayout, AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroU32: KnownLayout, AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroI32: KnownLayout, AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroU64: KnownLayout, AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroI64: KnownLayout, AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroU128: KnownLayout, AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroI128: KnownLayout, AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroUsize: KnownLayout, AsBytes, !FromZeroes, !FromBytes, !Unaligned);
assert_impls!(NonZeroIsize: KnownLayout, AsBytes, !FromZeroes, !FromBytes, !Unaligned);

assert_impls!(Option<NonZeroU8>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(Option<NonZeroI8>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(Option<NonZeroU16>: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroI16>: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroU32>: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroI32>: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroU64>: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroI64>: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroU128>: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroI128>: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroUsize>: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);
assert_impls!(Option<NonZeroIsize>: KnownLayout, FromZeroes, FromBytes, AsBytes, !Unaligned);

// Implements none of the ZC traits.
struct NotZerocopy;

assert_impls!(PhantomData<NotZerocopy>: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(PhantomData<[u8]>: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(PhantomData<NotZerocopy>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(PhantomData<[u8]>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);

assert_impls!(ManuallyDrop<u8>: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(ManuallyDrop<[u8]>: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(ManuallyDrop<NotZerocopy>: !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
assert_impls!(ManuallyDrop<[NotZerocopy]>: !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
assert_impls!(ManuallyDrop<u8>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(ManuallyDrop<[u8]>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(ManuallyDrop<NotZerocopy>: !KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
assert_impls!(ManuallyDrop<[NotZerocopy]>: !KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);

assert_impls!(MaybeUninit<u8>: FromZeroes, FromBytes, Unaligned, !AsBytes);
assert_impls!(MaybeUninit<NotZerocopy>: !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
assert_impls!(MaybeUninit<u8>: KnownLayout, FromZeroes, FromBytes, Unaligned, !AsBytes);
assert_impls!(MaybeUninit<NotZerocopy>: KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);

assert_impls!(Wrapping<u8>: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(Wrapping<NotZerocopy>: !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
assert_impls!(Wrapping<u8>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(Wrapping<NotZerocopy>: KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);

assert_impls!(Unalign<u8>: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(Unalign<NotZerocopy>: Unaligned, !FromZeroes, !FromBytes, !AsBytes);
assert_impls!(Unalign<u8>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!(Unalign<NotZerocopy>: KnownLayout, Unaligned, !FromZeroes, !FromBytes, !AsBytes);

assert_impls!([u8]: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!([NotZerocopy]: !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
assert_impls!([u8; 0]: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!([NotZerocopy; 0]: !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
assert_impls!([u8; 1]: FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!([NotZerocopy; 1]: !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
assert_impls!([u8]: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!([NotZerocopy]: !KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
assert_impls!([u8; 0]: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!([NotZerocopy; 0]: KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
assert_impls!([u8; 1]: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
assert_impls!([NotZerocopy; 1]: KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);

#[cfg(feature = "simd")]
{
Expand Down
8 changes: 6 additions & 2 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,11 @@ macro_rules! impl_known_layout {
const _: () = {
use core::ptr::NonNull;

impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> sealed::KnownLayoutSealed for $ty {}
// SAFETY: Delegates safety to `DstLayout::for_type`.
unsafe impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> KnownLayout for $ty {
#[allow(clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {}

const LAYOUT: DstLayout = DstLayout::for_type::<$ty>();

// SAFETY: `.cast` preserves address and provenance.
Expand Down Expand Up @@ -245,8 +247,10 @@ macro_rules! unsafe_impl_known_layout {
const _: () = {
use core::ptr::NonNull;

impl<$($tyvar: ?Sized + KnownLayout)?> sealed::KnownLayoutSealed for $ty {}
unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty {
#[allow(clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait() {}

const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;

// SAFETY: All operations preserve address and provenance.
Expand Down
15 changes: 12 additions & 3 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,18 @@ pub(crate) mod testutil {
// Though `u64` has alignment 8 on some platforms, it's not guaranteed.
// By contrast, `AU64` is guaranteed to have alignment 8.
#[derive(
FromZeroes, FromBytes, AsBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone,
KnownLayout,
FromZeroes,
FromBytes,
AsBytes,
Eq,
PartialEq,
Ord,
PartialOrd,
Default,
Debug,
Copy,
Clone,
)]
#[repr(C, align(8))]
pub(crate) struct AU64(pub(crate) u64);
Expand All @@ -589,8 +600,6 @@ pub(crate) mod testutil {
Display::fmt(&self.0, f)
}
}

impl_known_layout!(AU64);
}

#[cfg(test)]
Expand Down
8 changes: 7 additions & 1 deletion src/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,16 @@ use super::*;
// [3] https://github.com/google/zerocopy/issues/209
#[allow(missing_debug_implementations)]
#[derive(Default, Copy)]
#[cfg_attr(any(feature = "derive", test), derive(FromZeroes, FromBytes, AsBytes, Unaligned))]
#[cfg_attr(
any(feature = "derive", test),
derive(KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned)
)]
#[repr(C, packed)]
pub struct Unalign<T>(T);

#[cfg(not(any(feature = "derive", test)))]
impl_known_layout!(T => Unalign<T>);

safety_comment! {
/// SAFETY:
/// - `Unalign<T>` is `repr(packed)`, so it is unaligned regardless of the
Expand Down
Loading