diff --git a/src/derive_util.rs b/src/derive_util.rs index 8f72ef09c6..ad2aa3c7f6 100644 --- a/src/derive_util.rs +++ b/src/derive_util.rs @@ -62,3 +62,48 @@ macro_rules! union_has_padding { false $(|| core::mem::size_of::<$t>() != core::mem::size_of::<$ts>())* }; } + +#[doc(hidden)] +pub use project::project as __project; + +/// Implements `TryFromBytes` for a struct type by delegating to existing +/// implementations for each of its fields. +/// +/// # Safety +/// +/// `$ty` must be a struct type, `$f` must list every field's name, and `$f_ty` +/// must be the correct types for those fields. +#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`. +#[macro_export] +macro_rules! impl_try_from_bytes_for_struct { + ($ty:ty { $($f:tt: $f_ty:ty),* } $(=> $validation_method:ident)?) => { + // SAFETY: The caller promises that all fields are listed with their + // correct types. We validate that every field is valid, which is the + // only requirement for the entire struct to be valid. Thus, we + // correctly implement `is_bit_valid` as required by the trait's safety + // documentation. + #[allow(unused_qualifications)] + unsafe impl zerocopy::TryFromBytes for $ty { + fn is_bit_valid(bytes: &zerocopy::MaybeValid) -> bool { + true $(&& { + let f: &zerocopy::MaybeValid<$f_ty> + = zerocopy::derive_util::__project!(&bytes.$f); + zerocopy::TryFromBytes::is_bit_valid(f) + })* + $(&& { + // SAFETY: We just validated that all of the struct's fields + // are valid, which means that the struct itself is valid. + // That is the only precondition of `assume_valid_ref`. + let slf = unsafe { bytes.assume_valid_ref() }; + // TODO: What about interior mutability? One approach would + // be to have the validation method operate on a + // `#[repr(transparent)]` `Freeze` container that implements + // `Projectable`. If we eventually get a `Freeze` or + // `NoCell` trait, that container could implement `Deref` + // for types which don't contain any cells. + slf.$validation_method() + })? + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index a0246ccc70..e72a138a2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -157,6 +157,8 @@ use core::{ ptr, slice, }; +use project::Projectable; + #[cfg(feature = "alloc")] extern crate alloc; #[cfg(feature = "alloc")] @@ -174,6 +176,81 @@ mod zerocopy { pub(crate) use crate::*; } +/// Documents multiple unsafe blocks with a single safety comment. +/// +/// Invoked as: +/// +/// ```rust,ignore +/// safety_comment! { +/// // Non-doc comments come first. +/// /// SAFETY: +/// /// Safety comment starts on its own line. +/// macro_1!(args); +/// macro_2! { args }; +/// } +/// ``` +/// +/// The macro invocations are emitted, each decorated with the following +/// attribute: `#[allow(clippy::undocumented_unsafe_blocks)]`. +macro_rules! safety_comment { + (#[doc = r" SAFETY:"] $(#[doc = $_doc:literal])* $($macro:ident!$args:tt;)*) => { + #[allow(clippy::undocumented_unsafe_blocks)] + const _: () = { $($macro!$args;)* }; + } +} + +/// Unsafely implements trait(s) for a type. +macro_rules! unsafe_impl { + // Implement `$trait` for `$ty` with no bounds. + ($ty:ty: $trait:ty) => { + unsafe impl $trait for $ty { fn only_derive_is_allowed_to_implement_this_trait() {} } + }; + // Implement all `$traits` for `$ty` with no bounds. + ($ty:ty: $($traits:ty),*) => { + $( unsafe_impl!($ty: $traits); )* + }; + // For all `$tyvar` with no bounds, implement `$trait` for `$ty`. + ($tyvar:ident => $trait:ident for $ty:ty) => { + unsafe impl<$tyvar> $trait for $ty { fn only_derive_is_allowed_to_implement_this_trait() {} } + }; + // For all `$tyvar: ?Sized` with no bounds, implement `$trait` for `$ty`. + ($tyvar:ident: ?Sized => $trait:ident for $ty:ty) => { + unsafe impl<$tyvar: ?Sized> $trait for $ty { fn only_derive_is_allowed_to_implement_this_trait() {} } + }; + // For all `$tyvar: $bound`, implement `$trait` for `$ty`. + ($tyvar:ident: $bound:path => $trait:ident for $ty:ty) => { + unsafe impl<$tyvar: $bound> $trait for $ty { fn only_derive_is_allowed_to_implement_this_trait() {} } + }; + // For all `$tyvar: $bound + ?Sized`, implement `$trait` for `$ty`. + ($tyvar:ident: ?Sized + $bound:path => $trait:ident for $ty:ty) => { + unsafe impl<$tyvar: ?Sized + $bound> $trait for $ty { fn only_derive_is_allowed_to_implement_this_trait() {} } + }; + // For all `$tyvar: $bound` and for all `const $constvar: $constty`, + // implement `$trait` for `$ty`. + ($tyvar:ident: $bound:path, const $constvar:ident: $constty:ty => $trait:ident for $ty:ty) => { + unsafe impl<$tyvar: $bound, const $constvar: $constty> $trait for $ty { + fn only_derive_is_allowed_to_implement_this_trait() {} + } + }; +} + +/// Uses `align_of` to confirm that a type or set of types have alignment 1. +/// +/// Note that `align_of` requires `T: Sized`, so this macro doesn't work for +/// unsized types. +macro_rules! assert_unaligned { + ($ty:ty) => { + // We only compile this assertion under `cfg(test)` to avoid taking an + // extra non-dev dependency (and making this crate more expensive to + // compile for our dependents). + #[cfg(test)] + static_assertions::const_assert_eq!(core::mem::align_of::<$ty>(), 1); + }; + ($($ty:ty),*) => { + $(assert_unaligned!($ty);)* + }; +} + /// Types for which a sequence of bytes all set to zero represents a valid /// instance of the type. /// @@ -499,6 +576,422 @@ pub unsafe trait FromBytes: FromZeroes { } } +/// TODO +/// +/// # Safety +/// +/// `AsMaybeUninit` must only be implemented for types which are `Sized` or +/// whose last field is a slice whose element type is `Sized` (this includes +/// slice types themselves; in a slice type, the "last field" simply refers to +/// the slice itself). +pub unsafe trait AsMaybeUninit { + /// TODO + /// + /// # Safety + /// + /// For `T: AsMaybeUninit`, the following must hold: + /// - Given `m: T::MaybeUninit`, it is sound to write uninitialized bytes at + /// every byte offset in `m` (this description avoids the "what lengths + /// are valid" problem) + /// - `T` and `T::MaybeUninit` have the same alignment requirement (can't + /// use `align_of` to describe this because it requires that its argument + /// is sized) + /// - `T` and `T::MaybeUninit` are either both `Sized` or both `!Sized` + /// - If they are `Sized`, `size_of::() == size_of::()` + /// - If they are `!Sized`, then they are both DSTs with a trailing slice. + /// Given `t: &T` and `m: &T::MaybeUninit` with the same number of + /// elements in their trailing slices, `size_of_val(t) == size_of_val(m)`. + type MaybeUninit: ?Sized + FromBytes; +} + +unsafe impl AsMaybeUninit for T { + type MaybeUninit = MaybeUninit; +} + +unsafe impl AsMaybeUninit for [T] { + type MaybeUninit = [MaybeUninit]; +} + +unsafe impl AsMaybeUninit for str { + type MaybeUninit = <[u8] as AsMaybeUninit>::MaybeUninit; +} + +/// A value which might or might not constitute a valid instance of `T`. +/// +/// `MaybeValid` has the same layout (size and alignment) and field offsets +/// as `T`. However, it may contain any bit pattern with a few restrictions: +/// Given `m: MaybeValid` and a byte offset, `b` in the range `[0, +/// size_of::>())`: +/// - If, in all valid instances `t: T`, the byte at offset `b` in `t` is +/// initialized, then the byte at offset `b` within `m` is guaranteed to be +/// initialized. +/// - Let `s` be the sequence of bytes of length `b` in the offset range `[0, +/// b)` in `m`. Let `TT` be the subset of valid instances of `T` which contain +/// this sequence in the offset range `[0, b)`. If, for all instances of `t: +/// T` in `TT`, the byte at offset `b` in `t` is initialized, then the byte at +/// offset `b` in `m` is guaranteed to be initialized. +/// +/// Pragmatically, this means that if `m` is guaranteed to contain an enum +/// type at a particular offset, and the enum discriminant stored in `m` +/// corresponds to a valid variant of that enum type, then it is guaranteed +/// that the appropriate bytes of `m` are initialized as defined by that +/// variant's layout (although note that the variant's layout may contain +/// another enum type, in which case the same rules apply depending on the +/// state of its discriminant, and so on recursively). +/// +/// # Safety +/// +/// TODO (make sure to mention enum layout) +#[derive(FromZeroes, FromBytes, Unaligned)] +#[repr(transparent)] +pub struct MaybeValid { + inner: T::MaybeUninit, +} + +safety_comment! { + /// SAFETY: + /// TODO + unsafe_impl!(T: AsBytes => AsBytes for MaybeValid); + unsafe_impl!(T: AsBytes => AsBytes for MaybeValid<[T]>); +} + +impl Default for MaybeValid { + fn default() -> MaybeValid { + MaybeValid { inner: MaybeUninit::uninit() } + } +} + +impl MaybeValid { + /// Converts this `MaybeValid` to a `T`. + /// + /// # Safety + /// + /// `self` must contain a valid `T`. + pub const unsafe fn assume_valid(self) -> T { + // SAFETY: The caller has promised that `self` contains a valid `T`. + // Since `T: Sized`, we know that `T::MaybeUninit = MaybeUninit`. + // Since `MaybeValid` is `repr(transparent)`, its layout is identical to + // the contained `MaybeUninit`. Thus, the promise that `self` contains a + // valid `T` implies that the contained `MaybeUninit` contains a valid + // `T`. + unsafe { self.inner.assume_init() } + } + + /// Converts this `&MaybeValid` to a `&T`. + /// + /// # Safety + /// + /// `self` must contain a valid `T`. + pub const unsafe fn assume_valid_ref(&self) -> &T { + // SAFETY: The caller has promised that `self` contains a valid `T`. + // Since `T: Sized`, we know that `T::MaybeUninit = MaybeUninit`. + // Since `MaybeValid` is `repr(transparent)`, its layout is identical to + // the contained `MaybeUninit`. Thus, the promise that `self` contains a + // valid `T` implies that the contained `MaybeUninit` contains a valid + // `T`. + unsafe { self.inner.assume_init_ref() } + } + + /// Converts this `&mut MaybeValid` to a `&mut T`. + /// + /// # Safety + /// + /// `self` must contain a valid `T`. + pub unsafe fn assume_valid_mut(&mut self) -> &mut T { + // SAFETY: The caller has promised that `self` contains a valid `T`. + // Since `T: Sized`, we know that `T::MaybeUninit = MaybeUninit`. + // Since `MaybeValid` is `repr(transparent)`, its layout is identical to + // the contained `MaybeUninit`. Thus, the promise that `self` contains a + // valid `T` implies that the contained `MaybeUninit` contains a valid + // `T`. + unsafe { self.inner.assume_init_mut() } + } +} + +impl MaybeValid<[T]> { + /// Converts a `MaybeValid<[T]>` to a `[MaybeValid]`. + /// + /// `MaybeValid` has the same layout as `T`, so these layouts are + /// equivalent. + pub const fn as_slice_of_maybe_valids(&self) -> &[MaybeValid] { + let inner: &[::MaybeUninit] = &self.inner; + let inner_ptr: *const [::MaybeUninit] = inner; + let ret_ptr = inner_ptr as *const [MaybeValid]; + // SAFETY: Since `inner` is a `&[T::MaybeUninit]`, and `MaybeValid` + // is a `repr(transparent)` struct around `T::MaybeUninit`, `inner` has + // the same layout as `&[MaybeValid]`. + unsafe { &*ret_ptr } + } +} + +impl MaybeValid<[T; N]> { + /// TODO + pub const fn as_slice(&self) -> &MaybeValid<[T]> { + todo!() + } +} + +unsafe impl Projectable> for MaybeValid { + type Inner = T; +} + +impl Debug for MaybeValid { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.pad(core::any::type_name::()) + } +} + +/// Types whose validity can be checked at runtime, allowing them to be +/// conditionally converted from byte slices. +/// +/// WARNING: Do not implement this trait yourself! Instead, use +/// `#[derive(TryFromBytes)]`. +/// +/// `TryFromBytes` types can safely be deserialized from an untrusted sequence +/// of bytes by performing a runtime check that the byte sequence contains a +/// valid instance of `Self`. +/// +/// `TryFromBytes` is ignorant of byte order. For byte order-aware types, see +/// the [`byteorder`] module. +/// +/// # Safety +/// +/// Unsafe code may assume that [`is_bit_valid`] is correct, that, if +/// `is_bit_valid(candidate)` returns true, `candidate` contains a valid `Self`, +/// and that it is sound to treat `candidate` as a `&Self`. +/// +/// Implementations of `TryFromBytes` must ensure that [`is_bit_valid`] +/// satisfies its documented safety invariants. +// TODO(#5): Describe in the documentation that `TryFromBytes` is compositional? +// Describe anything about the `is_bit_valid` impls that the custom derive +// emits? +pub unsafe trait TryFromBytes: AsMaybeUninit { + /// Does this [`MaybeValid`] contain a valid instance of `Self`? + /// + /// # Safety + /// + /// Unsafe code may assume that, if `is_bit_valid(candidate)` returns true, + /// `candidate` contains a valid `Self`, and that it is sound to treat + /// `candidate` as a `&Self`. + fn is_bit_valid(candidate: &MaybeValid) -> bool; + + /// Attempts to interpret a byte slice as a `Self`. + /// + /// `try_from_ref` validates that `bytes` contains a valid `Self` as defined + /// by [`is_bit_valid`]. If it does, then `bytes` is reinterpreted as a + /// `Self`. + /// + /// [`is_bit_valid`]: TryFromBytes::is_bit_valid + // TODO(#251): In a future in which we distinguish between `FromBytes` and + // `RefFromBytes`, this requires `where Self: RefFromBytes` to disallow + // interior mutability. + fn try_from_ref(bytes: &[u8]) -> Option<&Self> + where + // TODO(#5): Support unsized types. + Self: Sized, + { + // TODO(https://github.com/rust-lang/rust/issues/115080): Inline this + // function once #115080 is resolved. + #[inline(always)] + fn try_read_from_inner) -> bool>( + bytes: &[u8], + is_bit_valid: F, + ) -> Option<&T> { + let maybe_valid = Ref::<_, MaybeValid>::new(bytes)?.into_ref(); + if is_bit_valid(maybe_valid) { + // SAFETY: `is_bit_valid` promises that it only returns true if + // its argument contains a valid `T`. This is exactly the safety + // precondition of `MaybeValid::assume_valid_ref`. + Some(unsafe { maybe_valid.assume_valid_ref() }) + } else { + None + } + } + + try_read_from_inner(bytes, Self::is_bit_valid) + } + + /// Attempts to interpret a mutable byte slice as a `Self`. + /// + /// `try_from_mut` validates that `bytes` contains a valid `Self` as defined + /// by [`is_bit_valid`]. If it does, then `bytes` is reinterpreted as a + /// `Self`. + /// + /// [`is_bit_valid`]: TryFromBytes::is_bit_valid + // TODO(#251): In a future in which we distinguish between `FromBytes` and + // `RefFromBytes`, this requires `where Self: RefFromBytes` to disallow + // interior mutability. + fn try_from_mut(bytes: &mut [u8]) -> Option<&mut Self> + where + // TODO(#5): Support unsized types. + Self: AsBytes + Sized, + { + // TODO(https://github.com/rust-lang/rust/issues/115080): Inline this + // function once #115080 is resolved. + #[inline(always)] + fn try_read_from_mut_inner) -> bool>( + bytes: &mut [u8], + is_bit_valid: F, + ) -> Option<&mut T> { + let maybe_valid = Ref::<_, MaybeValid>::new(bytes)?.into_mut(); + if is_bit_valid(maybe_valid) { + // SAFETY: `is_bit_valid` promises that it only returns true if + // its argument contains a valid `T`. This is exactly the safety + // precondition of `MaybeValid::assume_valid_mut`. + Some(unsafe { maybe_valid.assume_valid_mut() }) + } else { + None + } + } + + try_read_from_mut_inner(bytes, Self::is_bit_valid) + } + + /// Attempts to read a `Self` from a byte slice. + /// + /// `try_read_from` validates that `bytes` contains a valid `Self` as + /// defined by [`is_bit_valid`]. If it does, then that `Self` is copied and + /// returned by-value. + /// + /// [`is_bit_valid`]: TryFromBytes::is_bit_valid + // TODO(#251): In a future in which we distinguish between `FromBytes` and + // `RefFromBytes`, this requires `where Self: RefFromBytes` to disallow + // interior mutability. + fn try_read_from(bytes: &[u8]) -> Option + where + Self: Sized, + { + // TODO(https://github.com/rust-lang/rust/issues/115080): Inline this + // function once #115080 is resolved. + #[inline(always)] + fn try_read_from_inner) -> bool>( + bytes: &[u8], + is_bit_valid: F, + ) -> Option { + // A note on performance: We unconditionally read `size_of::()` + // bytes into the local stack frame before validation. This has + // advantages and disadvantages: + // - It allows `MaybeValid` to be aligned to `T`, and thus allows + // `is_bit_valid` to operate on an aligned value. + // - It requires us to perform the copy even if validation fails. + // + // The authors believe that this is a worthwhile tradeoff. Allowing + // `is_bit_valid` to operate on an aligned value can make the + // generated machine code significantly smaller and faster. On the + // other hand, we expect the vast majority of calls to + // `try_read_from` to succeed, and in these cases, the copy will not + // be wasted. + let maybe_valid = MaybeValid::::read_from(bytes)?; + if is_bit_valid(&maybe_valid) { + // SAFETY: `is_bit_valid` promises that it only returns true if + // its argument contains a valid `T`. This is exactly the safety + // precondition of `MaybeValid::assume_valid`. + Some(unsafe { maybe_valid.assume_valid() }) + } else { + None + } + } + + try_read_from_inner(bytes, Self::is_bit_valid) + } +} + +unsafe impl TryFromBytes for T { + fn is_bit_valid(_candidate: &MaybeValid) -> bool { + true + } +} + +// TODO: This conflicts with the blanket impl for `T: TryFromBytes`. + +// unsafe impl TryFromBytes for [T; N] +// where +// // TODO: Why can't Rust infer this based on the blanket impl for `T: Sized`? +// // It sets `MaybeUninit = MaybeUninit`, which is `Sized`. +// ::MaybeUninit: Sized, +// { +// fn is_bit_valid(candidate: &MaybeValid<[T; N]>) -> bool { +// candidate.as_slice().as_slice_of_maybe_valids().iter().all(|c| T::is_bit_valid(c)) +// } +// } + +unsafe impl TryFromBytes for [T] +where + // TODO: Why can't Rust infer this based on the blanket impl for `T: Sized`? + // It sets `MaybeUninit = MaybeUninit`, which is `Sized`. + ::MaybeUninit: Sized, +{ + fn is_bit_valid(candidate: &MaybeValid<[T]>) -> bool { + candidate.as_slice_of_maybe_valids().iter().all(|c| T::is_bit_valid(c)) + } +} + +/// # Safety +/// +/// It must be sound to transmute `&MaybeValid<$ty>` into `&$repr`. +macro_rules! unsafe_impl_try_from_bytes { + ($ty:ty, $repr:ty, |$candidate:ident| $is_bit_valid:expr) => { + unsafe impl TryFromBytes for $ty { + fn is_bit_valid(candidate: &MaybeValid<$ty>) -> bool { + let $candidate = unsafe { &*(candidate as *const MaybeValid<$ty> as *const $repr) }; + $is_bit_valid + } + } + }; +} + +safety_comment! { + /// SAFETY: + /// All of the `NonZeroXxx` types have the same layout as `Xxx`. Also, every + /// byte of such a type is required to be initialized, so it is guaranteed + /// that every byte of a `MaybeValid` must also be initialized. + /// Thus, it is sound to transmute a `&MaybeValid` to a `&Xxx`. + /// + /// TODO: Why are these impls correct (ie, ensure valid NonZeroXxx types)? + unsafe_impl_try_from_bytes!(NonZeroU8, u8, |n| *n != 0); + unsafe_impl_try_from_bytes!(NonZeroU16, u16, |n| *n != 0); + unsafe_impl_try_from_bytes!(NonZeroU32, u32, |n| *n != 0); + unsafe_impl_try_from_bytes!(NonZeroU64, u64, |n| *n != 0); + unsafe_impl_try_from_bytes!(NonZeroU128, u128, |n| *n != 0); + unsafe_impl_try_from_bytes!(NonZeroUsize, usize, |n| *n != 0); + unsafe_impl_try_from_bytes!(NonZeroI8, i8, |n| *n != 0); + unsafe_impl_try_from_bytes!(NonZeroI16, i16, |n| *n != 0); + unsafe_impl_try_from_bytes!(NonZeroI32, i32, |n| *n != 0); + unsafe_impl_try_from_bytes!(NonZeroI64, i64, |n| *n != 0); + unsafe_impl_try_from_bytes!(NonZeroI128, i128, |n| *n != 0); + unsafe_impl_try_from_bytes!(NonZeroIsize, isize, |n| *n != 0); +} + +unsafe_impl_try_from_bytes!(bool, u8, |byte| *byte < 2); + +unsafe_impl_try_from_bytes!(char, [u8; 4], |bytes| { + let c = u32::from_ne_bytes(*bytes); + char::from_u32(c).is_some() +}); + +unsafe_impl_try_from_bytes!(str, [u8], |bytes| core::str::from_utf8(bytes).is_ok()); + +mod try_from_bytes_derive_example { + use super::*; + + struct Foo { + a: u8, + b: u16, + } + + impl_try_from_bytes_for_struct!(Foo { a: u8, b: u16 }); + + struct Bar(Foo); + + impl Bar { + fn is_valid(&self) -> bool { + u16::from(self.0.a) < self.0.b + } + } + + impl_try_from_bytes_for_struct!(Bar { 0: Foo } => is_valid); +} + /// Types which are safe to treat as an immutable byte slice. /// /// WARNING: Do not implement this trait yourself! Instead, use @@ -696,81 +1189,6 @@ pub unsafe trait Unaligned { Self: Sized; } -/// Documents multiple unsafe blocks with a single safety comment. -/// -/// Invoked as: -/// -/// ```rust,ignore -/// safety_comment! { -/// // Non-doc comments come first. -/// /// SAFETY: -/// /// Safety comment starts on its own line. -/// macro_1!(args); -/// macro_2! { args }; -/// } -/// ``` -/// -/// The macro invocations are emitted, each decorated with the following -/// attribute: `#[allow(clippy::undocumented_unsafe_blocks)]`. -macro_rules! safety_comment { - (#[doc = r" SAFETY:"] $(#[doc = $_doc:literal])* $($macro:ident!$args:tt;)*) => { - #[allow(clippy::undocumented_unsafe_blocks)] - const _: () = { $($macro!$args;)* }; - } -} - -/// Unsafely implements trait(s) for a type. -macro_rules! unsafe_impl { - // Implement `$trait` for `$ty` with no bounds. - ($ty:ty: $trait:ty) => { - unsafe impl $trait for $ty { fn only_derive_is_allowed_to_implement_this_trait() {} } - }; - // Implement all `$traits` for `$ty` with no bounds. - ($ty:ty: $($traits:ty),*) => { - $( unsafe_impl!($ty: $traits); )* - }; - // For all `$tyvar` with no bounds, implement `$trait` for `$ty`. - ($tyvar:ident => $trait:ident for $ty:ty) => { - unsafe impl<$tyvar> $trait for $ty { fn only_derive_is_allowed_to_implement_this_trait() {} } - }; - // For all `$tyvar: ?Sized` with no bounds, implement `$trait` for `$ty`. - ($tyvar:ident: ?Sized => $trait:ident for $ty:ty) => { - unsafe impl<$tyvar: ?Sized> $trait for $ty { fn only_derive_is_allowed_to_implement_this_trait() {} } - }; - // For all `$tyvar: $bound`, implement `$trait` for `$ty`. - ($tyvar:ident: $bound:path => $trait:ident for $ty:ty) => { - unsafe impl<$tyvar: $bound> $trait for $ty { fn only_derive_is_allowed_to_implement_this_trait() {} } - }; - // For all `$tyvar: $bound + ?Sized`, implement `$trait` for `$ty`. - ($tyvar:ident: ?Sized + $bound:path => $trait:ident for $ty:ty) => { - unsafe impl<$tyvar: ?Sized + $bound> $trait for $ty { fn only_derive_is_allowed_to_implement_this_trait() {} } - }; - // For all `$tyvar: $bound` and for all `const $constvar: $constty`, - // implement `$trait` for `$ty`. - ($tyvar:ident: $bound:path, const $constvar:ident: $constty:ty => $trait:ident for $ty:ty) => { - unsafe impl<$tyvar: $bound, const $constvar: $constty> $trait for $ty { - fn only_derive_is_allowed_to_implement_this_trait() {} - } - }; -} - -/// Uses `align_of` to confirm that a type or set of types have alignment 1. -/// -/// Note that `align_of` requires `T: Sized`, so this macro doesn't work for -/// unsized types. -macro_rules! assert_unaligned { - ($ty:ty) => { - // We only compile this assertion under `cfg(test)` to avoid taking an - // extra non-dev dependency (and making this crate more expensive to - // compile for our dependents). - #[cfg(test)] - static_assertions::const_assert_eq!(core::mem::align_of::<$ty>(), 1); - }; - ($($ty:ty),*) => { - $(assert_unaligned!($ty);)* - }; -} - safety_comment! { /// SAFETY: /// Per the reference [1], "the unit tuple (`()`) ... is guaranteed as a