summaryrefslogtreecommitdiff
path: root/rust/zerocopy/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'rust/zerocopy/src/util')
-rw-r--r--rust/zerocopy/src/util/macro_util.rs1310
-rw-r--r--rust/zerocopy/src/util/macros.rs1067
-rw-r--r--rust/zerocopy/src/util/mod.rs944
3 files changed, 3321 insertions, 0 deletions
diff --git a/rust/zerocopy/src/util/macro_util.rs b/rust/zerocopy/src/util/macro_util.rs
new file mode 100644
index 000000000000..ceeb80432b0b
--- /dev/null
+++ b/rust/zerocopy/src/util/macro_util.rs
@@ -0,0 +1,1310 @@
+// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT
+//
+// Copyright 2022 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+//! Utilities used by macros and by `zerocopy-derive`.
+//!
+//! These are defined here `zerocopy` rather than in code generated by macros or
+//! by `zerocopy-derive` so that they can be compiled once rather than
+//! recompiled for every invocation (e.g., if they were defined in generated
+//! code, then deriving `IntoBytes` and `FromBytes` on three different types
+//! would result in the code in question being emitted and compiled six
+//! different times).
+
+#![allow(missing_debug_implementations)]
+
+// FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove
+// this `cfg` when `size_of_val_raw` is stabilized.
+#[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)]
+#[cfg(not(target_pointer_width = "16"))]
+use core::ptr::{self, NonNull};
+use core::{marker::PhantomData, mem, num::Wrapping};
+
+use crate::{
+ pointer::{
+ cast::CastSized,
+ invariant::{Aligned, Initialized, Valid},
+ BecauseImmutable,
+ },
+ FromBytes, Immutable, IntoBytes, KnownLayout, Ptr, ReadOnly, TryFromBytes, ValidityError,
+};
+
+/// Projects the type of the field at `Index` in `Self` without regard for field
+/// privacy.
+///
+/// The `Index` parameter is any sort of handle that identifies the field; its
+/// definition is the obligation of the implementer.
+///
+/// # Safety
+///
+/// Unsafe code may assume that this accurately reflects the definition of
+/// `Self`.
+pub unsafe trait Field<Index> {
+ /// The type of the field at `Index`.
+ type Type: ?Sized;
+}
+
+#[cfg_attr(
+ not(no_zerocopy_diagnostic_on_unimplemented_1_78_0),
+ diagnostic::on_unimplemented(
+ message = "`{T}` has {PADDING_BYTES} total byte(s) of padding",
+ label = "types with padding cannot implement `IntoBytes`",
+ note = "consider using `zerocopy::Unalign` to lower the alignment of individual fields",
+ note = "consider adding explicit fields where padding would be",
+ note = "consider using `#[repr(packed)]` to remove padding"
+ )
+)]
+pub trait PaddingFree<T: ?Sized, const PADDING_BYTES: usize> {}
+impl<T: ?Sized> PaddingFree<T, 0> for () {}
+
+// FIXME(#1112): In the slice DST case, we should delegate to *both*
+// `PaddingFree` *and* `DynamicPaddingFree` (and probably rename `PaddingFree`
+// to `StaticPaddingFree` or something - or introduce a third trait with that
+// name) so that we can have more clear error messages.
+
+#[cfg_attr(
+ not(no_zerocopy_diagnostic_on_unimplemented_1_78_0),
+ diagnostic::on_unimplemented(
+ message = "`{T}` has one or more padding bytes",
+ label = "types with padding cannot implement `IntoBytes`",
+ note = "consider using `zerocopy::Unalign` to lower the alignment of individual fields",
+ note = "consider adding explicit fields where padding would be",
+ note = "consider using `#[repr(packed)]` to remove padding"
+ )
+)]
+pub trait DynamicPaddingFree<T: ?Sized, const HAS_PADDING: bool> {}
+impl<T: ?Sized> DynamicPaddingFree<T, false> for () {}
+
+#[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)]
+#[cfg(not(target_pointer_width = "16"))]
+const _64K: usize = 1 << 16;
+
+// FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove
+// this `cfg` when `size_of_val_raw` is stabilized.
+#[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)]
+#[cfg(not(target_pointer_width = "16"))]
+#[repr(C, align(65536))]
+struct Aligned64kAllocation([u8; _64K]);
+
+/// A pointer to an aligned allocation of size 2^16.
+///
+/// # Safety
+///
+/// `ALIGNED_64K_ALLOCATION` is guaranteed to point to the entirety of an
+/// allocation with size and alignment 2^16, and to have valid provenance.
+// FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove
+// this `cfg` when `size_of_val_raw` is stabilized.
+#[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)]
+#[cfg(not(target_pointer_width = "16"))]
+pub const ALIGNED_64K_ALLOCATION: NonNull<[u8]> = {
+ const REF: &Aligned64kAllocation = &Aligned64kAllocation([0; _64K]);
+ let ptr: *const Aligned64kAllocation = REF;
+ let ptr: *const [u8] = ptr::slice_from_raw_parts(ptr.cast(), _64K);
+ // SAFETY:
+ // - `ptr` is derived from a Rust reference, which is guaranteed to be
+ // non-null.
+ // - `ptr` is derived from an `&Aligned64kAllocation`, which has size and
+ // alignment `_64K` as promised. Its length is initialized to `_64K`,
+ // which means that it refers to the entire allocation.
+ // - `ptr` is derived from a Rust reference, which is guaranteed to have
+ // valid provenance.
+ //
+ // FIXME(#429): Once `NonNull::new_unchecked` docs document that it
+ // preserves provenance, cite those docs.
+ // FIXME: Replace this `as` with `ptr.cast_mut()` once our MSRV >= 1.65
+ #[allow(clippy::as_conversions)]
+ unsafe {
+ NonNull::new_unchecked(ptr as *mut _)
+ }
+};
+
+/// Computes the offset of the base of the field `$trailing_field_name` within
+/// the type `$ty`.
+///
+/// `trailing_field_offset!` produces code which is valid in a `const` context.
+// FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove
+// this `cfg` when `size_of_val_raw` is stabilized.
+#[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)]
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! trailing_field_offset {
+ ($ty:ty, $trailing_field_name:tt) => {{
+ let min_size = {
+ let zero_elems: *const [()] =
+ $crate::util::macro_util::core_reexport::ptr::slice_from_raw_parts(
+ $crate::util::macro_util::core_reexport::ptr::NonNull::<()>::dangling()
+ .as_ptr()
+ .cast_const(),
+ 0,
+ );
+ // SAFETY:
+ // - If `$ty` is `Sized`, `size_of_val_raw` is always safe to call.
+ // - Otherwise:
+ // - If `$ty` is not a slice DST, this pointer conversion will
+ // fail due to "mismatched vtable kinds", and compilation will
+ // fail.
+ // - If `$ty` is a slice DST, we have constructed `zero_elems` to
+ // have zero trailing slice elements. Per the `size_of_val_raw`
+ // docs, "For the special case where the dynamic tail length is
+ // 0, this function is safe to call." [1]
+ //
+ // [1] https://doc.rust-lang.org/nightly/std/mem/fn.size_of_val_raw.html
+ unsafe {
+ #[allow(clippy::as_conversions)]
+ $crate::util::macro_util::core_reexport::mem::size_of_val_raw(
+ zero_elems as *const $ty,
+ )
+ }
+ };
+
+ assert!(min_size <= _64K);
+
+ #[allow(clippy::as_conversions)]
+ let ptr = ALIGNED_64K_ALLOCATION.as_ptr() as *const $ty;
+
+ // SAFETY:
+ // - Thanks to the preceding `assert!`, we know that the value with zero
+ // elements fits in `_64K` bytes, and thus in the allocation addressed
+ // by `ALIGNED_64K_ALLOCATION`. The offset of the trailing field is
+ // guaranteed to be no larger than this size, so this field projection
+ // is guaranteed to remain in-bounds of its allocation.
+ // - Because the minimum size is no larger than `_64K` bytes, and
+ // because an object's size must always be a multiple of its alignment
+ // [1], we know that `$ty`'s alignment is no larger than `_64K`. The
+ // allocation addressed by `ALIGNED_64K_ALLOCATION` is guaranteed to
+ // be aligned to `_64K`, so `ptr` is guaranteed to satisfy `$ty`'s
+ // alignment.
+ // - As required by `addr_of!`, we do not write through `field`.
+ //
+ // Note that, as of [2], this requirement is technically unnecessary
+ // for Rust versions >= 1.75.0, but no harm in guaranteeing it anyway
+ // until we bump our MSRV.
+ //
+ // [1] Per https://doc.rust-lang.org/reference/type-layout.html:
+ //
+ // The size of a value is always a multiple of its alignment.
+ //
+ // [2] https://github.com/rust-lang/reference/pull/1387
+ let field = unsafe {
+ $crate::util::macro_util::core_reexport::ptr::addr_of!((*ptr).$trailing_field_name)
+ };
+ // SAFETY:
+ // - Both `ptr` and `field` are derived from the same allocated object.
+ // - By the preceding safety comment, `field` is in bounds of that
+ // allocated object.
+ // - The distance, in bytes, between `ptr` and `field` is required to be
+ // a multiple of the size of `u8`, which is trivially true because
+ // `u8`'s size is 1.
+ // - The distance, in bytes, cannot overflow `isize`. This is guaranteed
+ // because no allocated object can have a size larger than can fit in
+ // `isize`. [1]
+ // - The distance being in-bounds cannot rely on wrapping around the
+ // address space. This is guaranteed because the same is guaranteed of
+ // allocated objects. [1]
+ //
+ // [1] FIXME(#429), FIXME(https://github.com/rust-lang/rust/pull/116675):
+ // Once these are guaranteed in the Reference, cite it.
+ let offset = unsafe { field.cast::<u8>().offset_from(ptr.cast::<u8>()) };
+ // Guaranteed not to be lossy: `field` comes after `ptr`, so the offset
+ // from `ptr` to `field` is guaranteed to be positive.
+ assert!(offset >= 0);
+ Some(
+ #[allow(clippy::as_conversions)]
+ {
+ offset as usize
+ },
+ )
+ }};
+}
+
+/// Computes alignment of `$ty: ?Sized`.
+///
+/// `align_of!` produces code which is valid in a `const` context.
+// FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835): Remove
+// this `cfg` when `size_of_val_raw` is stabilized.
+#[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)]
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! align_of {
+ ($ty:ty) => {{
+ // SAFETY: `OffsetOfTrailingIsAlignment` is `repr(C)`, and its layout is
+ // guaranteed [1] to begin with the single-byte layout for `_byte`,
+ // followed by the padding needed to align `_trailing`, then the layout
+ // for `_trailing`, and finally any trailing padding bytes needed to
+ // correctly-align the entire struct.
+ //
+ // This macro computes the alignment of `$ty` by counting the number of
+ // bytes preceding `_trailing`. For instance, if the alignment of `$ty`
+ // is `1`, then no padding is required align `_trailing` and it will be
+ // located immediately after `_byte` at offset 1. If the alignment of
+ // `$ty` is 2, then a single padding byte is required before
+ // `_trailing`, and `_trailing` will be located at offset 2.
+
+ // This correspondence between offset and alignment holds for all valid
+ // Rust alignments, and we confirm this exhaustively (or, at least up to
+ // the maximum alignment supported by `trailing_field_offset!`) in
+ // `test_align_of_dst`.
+ //
+ // [1]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprc
+
+ #[repr(C)]
+ struct OffsetOfTrailingIsAlignment {
+ _byte: u8,
+ _trailing: $ty,
+ }
+
+ trailing_field_offset!(OffsetOfTrailingIsAlignment, _trailing)
+ }};
+}
+
+mod size_to_tag {
+ pub trait SizeToTag<const SIZE: usize> {
+ type Tag;
+ }
+
+ impl SizeToTag<1> for () {
+ type Tag = u8;
+ }
+ impl SizeToTag<2> for () {
+ type Tag = u16;
+ }
+ impl SizeToTag<4> for () {
+ type Tag = u32;
+ }
+ impl SizeToTag<8> for () {
+ type Tag = u64;
+ }
+ impl SizeToTag<16> for () {
+ type Tag = u128;
+ }
+}
+
+/// An alias for the unsigned integer of the given size in bytes.
+#[doc(hidden)]
+pub type SizeToTag<const SIZE: usize> = <() as size_to_tag::SizeToTag<SIZE>>::Tag;
+
+// We put `Sized` in its own module so it can have the same name as the standard
+// library `Sized` without shadowing it in the parent module.
+#[cfg(not(no_zerocopy_diagnostic_on_unimplemented_1_78_0))]
+mod __size_of {
+ #[diagnostic::on_unimplemented(
+ message = "`{Self}` is unsized",
+ label = "`IntoBytes` needs all field types to be `Sized` in order to determine whether there is padding",
+ note = "consider using `#[repr(packed)]` to remove padding",
+ note = "`IntoBytes` does not require the fields of `#[repr(packed)]` types to be `Sized`"
+ )]
+ pub trait Sized: core::marker::Sized {}
+ impl<T: core::marker::Sized> Sized for T {}
+
+ #[inline(always)]
+ #[must_use]
+ #[allow(clippy::needless_maybe_sized)]
+ pub const fn size_of<T: Sized + ?core::marker::Sized>() -> usize {
+ core::mem::size_of::<T>()
+ }
+}
+
+#[cfg(no_zerocopy_diagnostic_on_unimplemented_1_78_0)]
+pub use core::mem::size_of;
+
+#[cfg(not(no_zerocopy_diagnostic_on_unimplemented_1_78_0))]
+pub use __size_of::size_of;
+
+/// How many padding bytes does the struct type `$t` have?
+///
+/// `$ts` is the list of the type of every field in `$t`. `$t` must be a struct
+/// type, or else `struct_padding!`'s result may be meaningless.
+///
+/// Note that `struct_padding!`'s results are independent of `repcr` since they
+/// only consider the size of the type and the sizes of the fields. Whatever the
+/// repr, the size of the type already takes into account any padding that the
+/// compiler has decided to add. Structs with well-defined representations (such
+/// as `repr(C)`) can use this macro to check for padding. Note that while this
+/// may yield some consistent value for some `repr(Rust)` structs, it is not
+/// guaranteed across platforms or compilations.
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! struct_padding {
+ ($t:ty, $_align:expr, $_packed:expr, [$($ts:ty),*]) => {{
+ // The `align` and `packed` directives can be ignored here. Regardless
+ // of if and how they are set, comparing the size of `$t` to the sum of
+ // its field sizes is a reliable indicator of the presence of padding.
+ $crate::util::macro_util::size_of::<$t>() - (0 $(+ $crate::util::macro_util::size_of::<$ts>())*)
+ }};
+}
+
+/// Does the `repr(C)` struct type `$t` have padding?
+///
+/// `$ts` is the list of the type of every field in `$t`. `$t` must be a
+/// `repr(C)` struct type, or else `struct_has_padding!`'s result may be
+/// meaningless.
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! repr_c_struct_has_padding {
+ ($t:ty, $align:expr, $packed:expr, [$($ts:tt),*]) => {{
+ let layout = $crate::DstLayout::for_repr_c_struct(
+ $align,
+ $packed,
+ &[$($crate::repr_c_struct_has_padding!(@field $ts),)*]
+ );
+ layout.requires_static_padding() || layout.requires_dynamic_padding()
+ }};
+ (@field ([$t:ty])) => {
+ <[$t] as $crate::KnownLayout>::LAYOUT
+ };
+ (@field ($t:ty)) => {
+ $crate::DstLayout::for_unpadded_type::<$t>()
+ };
+ (@field [$t:ty]) => {
+ <[$t] as $crate::KnownLayout>::LAYOUT
+ };
+ (@field $t:ty) => {
+ $crate::DstLayout::for_unpadded_type::<$t>()
+ };
+}
+
+/// Does the union type `$t` have padding?
+///
+/// `$ts` is the list of the type of every field in `$t`. `$t` must be a union
+/// type, or else `union_padding!`'s result may be meaningless.
+///
+/// Note that `union_padding!`'s results are independent of `repr` since they
+/// only consider the size of the type and the sizes of the fields. Whatever the
+/// repr, the size of the type already takes into account any padding that the
+/// compiler has decided to add. Unions with well-defined representations (such
+/// as `repr(C)`) can use this macro to check for padding. Note that while this
+/// may yield some consistent value for some `repr(Rust)` unions, it is not
+/// guaranteed across platforms or compilations.
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! union_padding {
+ ($t:ty, $_align:expr, $_packed:expr, [$($ts:ty),*]) => {{
+ // The `align` and `packed` directives can be ignored here. Regardless
+ // of if and how they are set, comparing the size of `$t` to each of its
+ // field sizes is a reliable indicator of the presence of padding.
+ let mut max = 0;
+ $({
+ let padding = $crate::util::macro_util::size_of::<$t>() - $crate::util::macro_util::size_of::<$ts>();
+ if padding > max {
+ max = padding;
+ }
+ })*
+ max
+ }};
+}
+
+/// How many padding bytes does the enum type `$t` have?
+///
+/// `$disc` is the type of the enum tag, and `$ts` is a list of fields in each
+/// square-bracket-delimited variant. `$t` must be an enum, or else
+/// `enum_padding!`'s result may be meaningless. An enum has padding if any of
+/// its variant structs [1][2] contain padding, and so all of the variants of an
+/// enum must be "full" in order for the enum to not have padding.
+///
+/// The results of `enum_padding!` require that the enum is not `repr(Rust)`, as
+/// `repr(Rust)` enums may niche the enum's tag and reduce the total number of
+/// bytes required to represent the enum as a result. As long as the enum is
+/// `repr(C)`, `repr(int)`, or `repr(C, int)`, this will consistently return
+/// whether the enum contains any padding bytes.
+///
+/// [1]: https://doc.rust-lang.org/1.81.0/reference/type-layout.html#reprc-enums-with-fields
+/// [2]: https://doc.rust-lang.org/1.81.0/reference/type-layout.html#primitive-representation-of-enums-with-fields
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! enum_padding {
+ ($t:ty, $_align:expr, $packed:expr, $disc:ty, $([$($ts:ty),*]),*) => {{
+ // The `align` and `packed` directives are irrelevant. `$align` can be
+ // ignored because regardless of if and how it is set, comparing the
+ // size of `$t` to each of its field sizes is a reliable indicator of
+ // the presence of padding. `$packed` is irrelevant because it is
+ // forbidden on enums.
+ #[allow(clippy::as_conversions)]
+ const _: [(); 1] = [(); $packed.is_none() as usize];
+ let mut max = 0;
+ $({
+ let padding = $crate::util::macro_util::size_of::<$t>()
+ - (
+ $crate::util::macro_util::size_of::<$disc>()
+ $(+ $crate::util::macro_util::size_of::<$ts>())*
+ );
+ if padding > max {
+ max = padding;
+ }
+ })*
+ max
+ }};
+}
+
+/// Unwraps an infallible `Result`.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! into_inner {
+ ($e:expr) => {
+ match $e {
+ $crate::util::macro_util::core_reexport::result::Result::Ok(e) => e,
+ $crate::util::macro_util::core_reexport::result::Result::Err(i) => match i {},
+ }
+ };
+}
+
+/// Translates an identifier or tuple index into a numeric identifier.
+#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
+#[macro_export]
+macro_rules! ident_id {
+ ($field:ident) => {
+ $crate::util::macro_util::hash_name(stringify!($field))
+ };
+ ($field:literal) => {
+ $field
+ };
+}
+
+/// Computes the hash of a string.
+///
+/// NOTE(#2749) on hash collisions: This function's output only needs to be
+/// deterministic within a particular compilation. Thus, if a user ever reports
+/// a hash collision (very unlikely given the <= 16-byte special case), we can
+/// strengthen the hash function at that point and publish a new version. Since
+/// this is computed at compile time on small strings, we can easily use more
+/// expensive and higher-quality hash functions if need be.
+#[inline(always)]
+#[must_use]
+#[allow(clippy::as_conversions, clippy::indexing_slicing, clippy::arithmetic_side_effects)]
+pub const fn hash_name(name: &str) -> i128 {
+ let name = name.as_bytes();
+
+ // We guarantee freedom from hash collisions between any two strings of
+ // length 16 or less by having the hashes of such strings be equal to
+ // their value. There is still a possibility that such strings will have
+ // the same value as the hash of a string of length > 16.
+ if name.len() <= size_of::<u128>() {
+ let mut bytes = [0u8; 16];
+
+ let mut i = 0;
+ while i < name.len() {
+ bytes[i] = name[i];
+ i += 1;
+ }
+
+ return i128::from_ne_bytes(bytes);
+ };
+
+ // An implementation of FxHasher, although returning a u128. Probably
+ // not as strong as it could be, but probably more collision resistant
+ // than normal 64-bit FxHasher.
+ let mut hash = 0u128;
+ let mut i = 0;
+ while i < name.len() {
+ // This is just FxHasher's `0x517cc1b727220a95` constant
+ // concatenated back-to-back.
+ const K: u128 = 0x517cc1b727220a95517cc1b727220a95;
+ hash = (hash.rotate_left(5) ^ (name[i] as u128)).wrapping_mul(K);
+ i += 1;
+ }
+ i128::from_ne_bytes(hash.to_ne_bytes())
+}
+
+/// Attempts to transmute `Src` into `Dst`.
+///
+/// A helper for `try_transmute!`.
+///
+/// # Panics
+///
+/// `try_transmute` may either produce a post-monomorphization error or a panic
+/// if `Dst` is bigger than `Src`. Otherwise, `try_transmute` panics under the
+/// same circumstances as [`is_bit_valid`].
+///
+/// [`is_bit_valid`]: TryFromBytes::is_bit_valid
+#[inline(always)]
+pub fn try_transmute<Src, Dst>(src: Src) -> Result<Dst, ValidityError<Src, Dst>>
+where
+ Src: IntoBytes,
+ Dst: TryFromBytes,
+{
+ static_assert!(Src, Dst => mem::size_of::<Dst>() == mem::size_of::<Src>());
+
+ let mu_src = mem::MaybeUninit::new(src);
+ // SAFETY: `MaybeUninit` has no validity requirements.
+ let mu_dst: mem::MaybeUninit<ReadOnly<Dst>> =
+ unsafe { crate::util::transmute_unchecked(mu_src) };
+
+ let ptr = Ptr::from_ref(&mu_dst);
+
+ // SAFETY: Since `Src: IntoBytes`, and since `size_of::<Src>() ==
+ // size_of::<Dst>()` by the preceding assertion, all of `mu_dst`'s bytes are
+ // initialized. `MaybeUninit` has no validity requirements, so even if
+ // `ptr` is used to mutate its referent (which it actually can't be - it's
+ // a shared `ReadOnly` pointer), that won't violate its referent's validity.
+ let ptr = unsafe { ptr.assume_validity::<Initialized>() };
+ if Dst::is_bit_valid(ptr.cast::<_, CastSized, _>()) {
+ // SAFETY: Since `Dst::is_bit_valid`, we know that `ptr`'s referent is
+ // bit-valid for `Dst`. `ptr` points to `mu_dst`, and no intervening
+ // operations have mutated it, so it is a bit-valid `Dst`.
+ Ok(ReadOnly::into_inner(unsafe { mu_dst.assume_init() }))
+ } else {
+ // SAFETY: `MaybeUninit` has no validity requirements.
+ let mu_src: mem::MaybeUninit<Src> = unsafe { crate::util::transmute_unchecked(mu_dst) };
+ // SAFETY: `mu_dst`/`mu_src` was constructed from `src` and never
+ // modified, so it is still bit-valid.
+ Err(ValidityError::new(unsafe { mu_src.assume_init() }))
+ }
+}
+
+/// See `try_transmute_ref!` documentation.
+pub trait TryTransmuteRefDst<'a> {
+ type Dst: ?Sized;
+
+ /// See `try_transmute_ref!` documentation.
+ fn try_transmute_ref(self) -> Result<&'a Self::Dst, ValidityError<&'a Self::Src, Self::Dst>>
+ where
+ Self: TryTransmuteRefSrc<'a>,
+ Self::Src: IntoBytes + Immutable + KnownLayout,
+ Self::Dst: TryFromBytes + Immutable + KnownLayout;
+}
+
+pub trait TryTransmuteRefSrc<'a> {
+ type Src: ?Sized;
+}
+
+impl<'a, Src, Dst> TryTransmuteRefSrc<'a> for Wrap<&'a Src, &'a Dst>
+where
+ Src: ?Sized,
+ Dst: ?Sized,
+{
+ type Src = Src;
+}
+
+impl<'a, Src, Dst> TryTransmuteRefDst<'a> for Wrap<&'a Src, &'a Dst>
+where
+ Src: IntoBytes + Immutable + KnownLayout + ?Sized,
+ Dst: TryFromBytes + Immutable + KnownLayout + ?Sized,
+{
+ type Dst = Dst;
+
+ #[inline(always)]
+ fn try_transmute_ref(
+ self,
+ ) -> Result<
+ &'a Dst,
+ ValidityError<&'a <Wrap<&'a Src, &'a Dst> as TryTransmuteRefSrc<'a>>::Src, Dst>,
+ > {
+ let ptr = Ptr::from_ref(self.0);
+ #[rustfmt::skip]
+ let res = ptr.try_with(#[inline(always)] |ptr| {
+ let ptr = ptr.recall_validity::<Initialized, _>();
+ let ptr = ptr.cast::<_, crate::layout::CastFrom<Dst>, _>();
+ ptr.try_into_valid()
+ });
+ match res {
+ Ok(ptr) => {
+ static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => {
+ Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get()
+ }, "cannot transmute reference when destination type has higher alignment than source type");
+ // SAFETY: We have checked that `Dst` does not have a stricter
+ // alignment requirement than `Src`.
+ let ptr = unsafe { ptr.assume_alignment::<Aligned>() };
+ Ok(ptr.as_ref())
+ }
+ Err(err) => Err(err.map_src(Ptr::as_ref)),
+ }
+ }
+}
+
+pub trait TryTransmuteMutDst<'a> {
+ type Dst: ?Sized;
+
+ /// See `try_transmute_mut!` documentation.
+ fn try_transmute_mut(
+ self,
+ ) -> Result<&'a mut Self::Dst, ValidityError<&'a mut Self::Src, Self::Dst>>
+ where
+ Self: TryTransmuteMutSrc<'a>,
+ Self::Src: IntoBytes,
+ Self::Dst: TryFromBytes;
+}
+
+pub trait TryTransmuteMutSrc<'a> {
+ type Src: ?Sized;
+}
+
+impl<'a, Src, Dst> TryTransmuteMutSrc<'a> for Wrap<&'a mut Src, &'a mut Dst>
+where
+ Src: ?Sized,
+ Dst: ?Sized,
+{
+ type Src = Src;
+}
+
+impl<'a, Src, Dst> TryTransmuteMutDst<'a> for Wrap<&'a mut Src, &'a mut Dst>
+where
+ Src: FromBytes + IntoBytes + KnownLayout + ?Sized,
+ Dst: TryFromBytes + IntoBytes + KnownLayout + ?Sized,
+{
+ type Dst = Dst;
+
+ #[inline(always)]
+ fn try_transmute_mut(
+ self,
+ ) -> Result<
+ &'a mut Dst,
+ ValidityError<&'a mut <Wrap<&'a mut Src, &'a mut Dst> as TryTransmuteMutSrc<'a>>::Src, Dst>,
+ > {
+ let ptr = Ptr::from_mut(self.0);
+ // SAFETY: The provided closure returns the only copy of `ptr`.
+ #[rustfmt::skip]
+ let res = unsafe {
+ ptr.try_with_unchecked(#[inline(always)] |ptr| {
+ let ptr = ptr.recall_validity::<Initialized, (_, (_, _))>();
+ let ptr = ptr.cast::<_, crate::layout::CastFrom<Dst>, _>();
+ ptr.try_into_valid()
+ })
+ };
+ match res {
+ Ok(ptr) => {
+ static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => {
+ Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get()
+ }, "cannot transmute reference when destination type has higher alignment than source type");
+ // SAFETY: We have checked that `Dst` does not have a stricter
+ // alignment requirement than `Src`.
+ let ptr = unsafe { ptr.assume_alignment::<Aligned>() };
+ Ok(ptr.as_mut())
+ }
+ Err(err) => Err(err.map_src(Ptr::as_mut)),
+ }
+ }
+}
+
+// Used in `transmute_ref!` and friends.
+//
+// This permits us to use the autoref specialization trick to dispatch to
+// associated functions for `transmute_ref` and `transmute_mut` when both `Src`
+// and `Dst` are `Sized`, and to trait methods otherwise. The associated
+// functions, unlike the trait methods, do not require a `KnownLayout` bound.
+// This permits us to add support for transmuting references to unsized types
+// without breaking backwards-compatibility (on v0.8.x) with the old
+// implementation, which did not require a `KnownLayout` bound to transmute
+// sized types.
+#[derive(Copy, Clone)]
+pub struct Wrap<Src, Dst>(pub Src, pub PhantomData<Dst>);
+
+impl<Src, Dst> Wrap<Src, Dst> {
+ #[inline(always)]
+ pub const fn new(src: Src) -> Self {
+ Wrap(src, PhantomData)
+ }
+}
+
+impl<'a, Src, Dst> Wrap<&'a Src, &'a Dst>
+where
+ Src: ?Sized,
+ Dst: ?Sized,
+{
+ #[allow(clippy::must_use_candidate, clippy::missing_inline_in_public_items, clippy::empty_loop)]
+ pub const fn transmute_ref_inference_helper(self) -> &'a Dst {
+ loop {}
+ }
+}
+
+impl<'a, Src, Dst> Wrap<&'a Src, &'a Dst> {
+ /// # Safety
+ /// The caller must guarantee that:
+ /// - `Src: IntoBytes + Immutable`
+ /// - `Dst: FromBytes + Immutable`
+ ///
+ /// # PME
+ ///
+ /// Instantiating this method PMEs unless both:
+ /// - `mem::size_of::<Dst>() == mem::size_of::<Src>()`
+ /// - `mem::align_of::<Dst>() <= mem::align_of::<Src>()`
+ #[inline(always)]
+ #[must_use]
+ pub const unsafe fn transmute_ref(self) -> &'a Dst {
+ static_assert!(Src, Dst => mem::size_of::<Dst>() == mem::size_of::<Src>());
+ static_assert!(Src, Dst => mem::align_of::<Dst>() <= mem::align_of::<Src>());
+
+ let src: *const Src = self.0;
+ let dst = src.cast::<Dst>();
+ // SAFETY:
+ // - We know that it is sound to view the target type of the input
+ // reference (`Src`) as the target type of the output reference
+ // (`Dst`) because the caller has guaranteed that `Src: IntoBytes`,
+ // `Dst: FromBytes`, and `size_of::<Src>() == size_of::<Dst>()`.
+ // - We know that there are no `UnsafeCell`s, and thus we don't have to
+ // worry about `UnsafeCell` overlap, because `Src: Immutable` and
+ // `Dst: Immutable`.
+ // - The caller has guaranteed that alignment is not increased.
+ // - We know that the returned lifetime will not outlive the input
+ // lifetime thanks to the lifetime bounds on this function.
+ //
+ // FIXME(#67): Once our MSRV is 1.58, replace this `transmute` with
+ // `&*dst`.
+ #[allow(clippy::transmute_ptr_to_ref)]
+ unsafe {
+ mem::transmute(dst)
+ }
+ }
+
+ #[inline(always)]
+ pub fn try_transmute_ref(self) -> Result<&'a Dst, ValidityError<&'a Src, Dst>>
+ where
+ Src: IntoBytes + Immutable,
+ Dst: TryFromBytes + Immutable,
+ {
+ static_assert!(Src => mem::align_of::<Src>() == mem::align_of::<Wrapping<Src>>());
+ static_assert!(Dst => mem::align_of::<Dst>() == mem::align_of::<Wrapping<Dst>>());
+
+ // SAFETY: By the preceding assert, `Src` and `Wrapping<Src>` have the
+ // same alignment.
+ let src: &Wrapping<Src> =
+ unsafe { crate::util::transmute_ref::<_, _, BecauseImmutable>(self.0) };
+ let src = Wrap::new(src);
+ <Wrap<&'a Wrapping<Src>, &'a Wrapping<Dst>> as TryTransmuteRefDst<'a>>::try_transmute_ref(
+ src,
+ )
+ .map(
+ // SAFETY: By the preceding assert, `Dst` and `Wrapping<Dst>` have
+ // the same alignment.
+ #[inline(always)]
+ |dst| unsafe { crate::util::transmute_ref::<_, _, BecauseImmutable>(dst) },
+ )
+ .map_err(
+ #[inline(always)]
+ |err| {
+ // SAFETY: By the preceding assert, `Src` and `Wrapping<Src>` have the
+ // same alignment.
+ ValidityError::new(unsafe {
+ crate::util::transmute_ref::<_, _, BecauseImmutable>(err.into_src())
+ })
+ },
+ )
+ }
+}
+
+impl<'a, Src, Dst> Wrap<&'a mut Src, &'a mut Dst>
+where
+ Src: ?Sized,
+ Dst: ?Sized,
+{
+ #[allow(clippy::must_use_candidate, clippy::missing_inline_in_public_items, clippy::empty_loop)]
+ pub fn transmute_mut_inference_helper(self) -> &'a mut Dst {
+ loop {}
+ }
+}
+
+impl<'a, Src, Dst> Wrap<&'a mut Src, &'a mut Dst> {
+ /// Transmutes a mutable reference of one type to a mutable reference of
+ /// another type.
+ ///
+ /// # PME
+ ///
+ /// Instantiating this method PMEs unless both:
+ /// - `mem::size_of::<Dst>() == mem::size_of::<Src>()`
+ /// - `mem::align_of::<Dst>() <= mem::align_of::<Src>()`
+ #[inline(always)]
+ #[must_use]
+ pub fn transmute_mut(self) -> &'a mut Dst
+ where
+ Src: FromBytes + IntoBytes,
+ Dst: FromBytes + IntoBytes,
+ {
+ static_assert!(Src, Dst => mem::size_of::<Dst>() == mem::size_of::<Src>());
+ static_assert!(Src, Dst => mem::align_of::<Dst>() <= mem::align_of::<Src>());
+
+ let src: *mut Src = self.0;
+ let dst = src.cast::<Dst>();
+ // SAFETY:
+ // - We know that it is sound to view the target type of the input
+ // reference (`Src`) as the target type of the output reference
+ // (`Dst`) and vice-versa because `Src: FromBytes + IntoBytes`, `Dst:
+ // FromBytes + IntoBytes`, and (as asserted above) `size_of::<Src>()
+ // == size_of::<Dst>()`.
+ // - We asserted above that alignment will not increase.
+ // - We know that the returned lifetime will not outlive the input
+ // lifetime thanks to the lifetime bounds on this function.
+ unsafe { &mut *dst }
+ }
+
+ #[inline(always)]
+ pub fn try_transmute_mut(self) -> Result<&'a mut Dst, ValidityError<&'a mut Src, Dst>>
+ where
+ Src: FromBytes + IntoBytes,
+ Dst: TryFromBytes + IntoBytes,
+ {
+ static_assert!(Src => mem::align_of::<Src>() == mem::align_of::<Wrapping<Src>>());
+ static_assert!(Dst => mem::align_of::<Dst>() == mem::align_of::<Wrapping<Dst>>());
+
+ // SAFETY: By the preceding assert, `Src` and `Wrapping<Src>` have the
+ // same alignment.
+ let src: &mut Wrapping<Src> =
+ unsafe { crate::util::transmute_mut::<_, _, (_, (_, _))>(self.0) };
+ let src = Wrap::new(src);
+ <Wrap<&'a mut Wrapping<Src>, &'a mut Wrapping<Dst>> as TryTransmuteMutDst<'a>>
+ ::try_transmute_mut(src)
+ // SAFETY: By the preceding assert, `Dst` and `Wrapping<Dst>` have the
+ // same alignment.
+ .map(|dst| unsafe { crate::util::transmute_mut::<_, _, (_, (_, _))>(dst) })
+ .map_err(|err| {
+ // SAFETY: By the preceding assert, `Src` and `Wrapping<Src>` have the
+ // same alignment.
+ ValidityError::new(unsafe {
+ crate::util::transmute_mut::<_, _, (_, (_, _))>(err.into_src())
+ })
+ })
+ }
+}
+
+pub trait TransmuteRefDst<'a> {
+ type Dst: ?Sized;
+
+ #[must_use]
+ fn transmute_ref(self) -> &'a Self::Dst;
+}
+
+impl<'a, Src: ?Sized, Dst: ?Sized> TransmuteRefDst<'a> for Wrap<&'a Src, &'a Dst>
+where
+ Src: KnownLayout + IntoBytes + Immutable,
+ Dst: KnownLayout<PointerMetadata = usize> + FromBytes + Immutable,
+{
+ type Dst = Dst;
+
+ #[inline(always)]
+ fn transmute_ref(self) -> &'a Dst {
+ let ptr = Ptr::from_ref(self.0)
+ .recall_validity::<Initialized, _>()
+ .transmute_with::<Dst, Initialized, crate::layout::CastFrom<Dst>, (crate::pointer::BecauseMutationCompatible, _)>()
+ .recall_validity::<Valid, _>();
+
+ static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => {
+ Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get()
+ }, "cannot transmute reference when destination type has higher alignment than source type");
+
+ // SAFETY: The preceding `static_assert!` ensures that
+ // `Src::LAYOUT.align >= Dst::LAYOUT.align`. Since `self` is
+ // validly-aligned for `Src`, it is also validly-aligned for `Dst`.
+ let ptr = unsafe { ptr.assume_alignment() };
+
+ ptr.as_ref()
+ }
+}
+
+pub trait TransmuteMutDst<'a> {
+ type Dst: ?Sized;
+ #[must_use]
+ fn transmute_mut(self) -> &'a mut Self::Dst;
+}
+
+impl<'a, Src: ?Sized, Dst: ?Sized> TransmuteMutDst<'a> for Wrap<&'a mut Src, &'a mut Dst>
+where
+ Src: KnownLayout + FromBytes + IntoBytes,
+ Dst: KnownLayout<PointerMetadata = usize> + FromBytes + IntoBytes,
+{
+ type Dst = Dst;
+
+ #[inline(always)]
+ fn transmute_mut(self) -> &'a mut Dst {
+ let ptr = Ptr::from_mut(self.0)
+ .recall_validity::<Initialized, (_, (_, _))>()
+ .transmute_with::<Dst, Initialized, crate::layout::CastFrom<Dst>, _>()
+ .recall_validity::<Valid, (_, (_, _))>();
+
+ static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => {
+ Src::LAYOUT.align.get() >= Dst::LAYOUT.align.get()
+ }, "cannot transmute reference when destination type has higher alignment than source type");
+
+ // SAFETY: The preceding `static_assert!` ensures that
+ // `Src::LAYOUT.align >= Dst::LAYOUT.align`. Since `self` is
+ // validly-aligned for `Src`, it is also validly-aligned for `Dst`.
+ let ptr = unsafe { ptr.assume_alignment() };
+
+ ptr.as_mut()
+ }
+}
+
+/// A function which emits a warning if its return value is not used.
+#[must_use]
+#[inline(always)]
+pub const fn must_use<T>(t: T) -> T {
+ t
+}
+
+// NOTE: We can't change this to a `pub use core as core_reexport` until [1] is
+// fixed or we update to a semver-breaking version (as of this writing, 0.8.0)
+// on the `main` branch.
+//
+// [1] https://github.com/obi1kenobi/cargo-semver-checks/issues/573
+pub mod core_reexport {
+ pub use core::*;
+
+ pub mod mem {
+ pub use core::mem::*;
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use core::num::NonZeroUsize;
+
+ use crate::util::testutil::*;
+
+ #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)]
+ mod nightly {
+ use super::super::*;
+ use crate::util::testutil::*;
+
+ // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835):
+ // Remove this `cfg` when `size_of_val_raw` is stabilized.
+ #[allow(clippy::decimal_literal_representation)]
+ #[test]
+ fn test_trailing_field_offset() {
+ assert_eq!(mem::align_of::<Aligned64kAllocation>(), _64K);
+
+ macro_rules! test {
+ (#[$cfg:meta] ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => {{
+ #[$cfg]
+ struct Test($(#[allow(dead_code)] $ts,)* #[allow(dead_code)] $trailing_field_ty);
+ assert_eq!(test!(@offset $($ts),* ; $trailing_field_ty), $expect);
+ }};
+ (#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),* ; $trailing_field_ty:ty) => $expect:expr) => {
+ test!(#[$cfg] ($($ts),* ; $trailing_field_ty) => $expect);
+ test!($(#[$cfgs])* ($($ts),* ; $trailing_field_ty) => $expect);
+ };
+ (@offset ; $_trailing:ty) => { trailing_field_offset!(Test, 0) };
+ (@offset $_t:ty ; $_trailing:ty) => { trailing_field_offset!(Test, 1) };
+ }
+
+ test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; u8) => Some(0));
+ test!(#[repr(C)] #[repr(transparent)] #[repr(packed)](; [u8]) => Some(0));
+ test!(#[repr(C)] #[repr(C, packed)] (u8; u8) => Some(1));
+ test!(#[repr(C)] (; AU64) => Some(0));
+ test!(#[repr(C)] (; [AU64]) => Some(0));
+ test!(#[repr(C)] (u8; AU64) => Some(8));
+ test!(#[repr(C)] (u8; [AU64]) => Some(8));
+
+ #[derive(
+ Immutable, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone,
+ )]
+ #[repr(C)]
+ pub(crate) struct Nested<T, U: ?Sized> {
+ _t: T,
+ _u: U,
+ }
+
+ test!(#[repr(C)] (; Nested<u8, AU64>) => Some(0));
+ test!(#[repr(C)] (; Nested<u8, [AU64]>) => Some(0));
+ test!(#[repr(C)] (u8; Nested<u8, AU64>) => Some(8));
+ test!(#[repr(C)] (u8; Nested<u8, [AU64]>) => Some(8));
+
+ // Test that `packed(N)` limits the offset of the trailing field.
+ test!(#[repr(C, packed( 1))] (u8; elain::Align< 2>) => Some( 1));
+ test!(#[repr(C, packed( 2))] (u8; elain::Align< 4>) => Some( 2));
+ test!(#[repr(C, packed( 4))] (u8; elain::Align< 8>) => Some( 4));
+ test!(#[repr(C, packed( 8))] (u8; elain::Align< 16>) => Some( 8));
+ test!(#[repr(C, packed( 16))] (u8; elain::Align< 32>) => Some( 16));
+ test!(#[repr(C, packed( 32))] (u8; elain::Align< 64>) => Some( 32));
+ test!(#[repr(C, packed( 64))] (u8; elain::Align< 128>) => Some( 64));
+ test!(#[repr(C, packed( 128))] (u8; elain::Align< 256>) => Some( 128));
+ test!(#[repr(C, packed( 256))] (u8; elain::Align< 512>) => Some( 256));
+ test!(#[repr(C, packed( 512))] (u8; elain::Align< 1024>) => Some( 512));
+ test!(#[repr(C, packed( 1024))] (u8; elain::Align< 2048>) => Some( 1024));
+ test!(#[repr(C, packed( 2048))] (u8; elain::Align< 4096>) => Some( 2048));
+ test!(#[repr(C, packed( 4096))] (u8; elain::Align< 8192>) => Some( 4096));
+ test!(#[repr(C, packed( 8192))] (u8; elain::Align< 16384>) => Some( 8192));
+ test!(#[repr(C, packed( 16384))] (u8; elain::Align< 32768>) => Some( 16384));
+ test!(#[repr(C, packed( 32768))] (u8; elain::Align< 65536>) => Some( 32768));
+ test!(#[repr(C, packed( 65536))] (u8; elain::Align< 131072>) => Some( 65536));
+ /* Alignments above 65536 are not yet supported.
+ test!(#[repr(C, packed( 131072))] (u8; elain::Align< 262144>) => Some( 131072));
+ test!(#[repr(C, packed( 262144))] (u8; elain::Align< 524288>) => Some( 262144));
+ test!(#[repr(C, packed( 524288))] (u8; elain::Align< 1048576>) => Some( 524288));
+ test!(#[repr(C, packed( 1048576))] (u8; elain::Align< 2097152>) => Some( 1048576));
+ test!(#[repr(C, packed( 2097152))] (u8; elain::Align< 4194304>) => Some( 2097152));
+ test!(#[repr(C, packed( 4194304))] (u8; elain::Align< 8388608>) => Some( 4194304));
+ test!(#[repr(C, packed( 8388608))] (u8; elain::Align< 16777216>) => Some( 8388608));
+ test!(#[repr(C, packed( 16777216))] (u8; elain::Align< 33554432>) => Some( 16777216));
+ test!(#[repr(C, packed( 33554432))] (u8; elain::Align< 67108864>) => Some( 33554432));
+ test!(#[repr(C, packed( 67108864))] (u8; elain::Align< 33554432>) => Some( 67108864));
+ test!(#[repr(C, packed( 33554432))] (u8; elain::Align<134217728>) => Some( 33554432));
+ test!(#[repr(C, packed(134217728))] (u8; elain::Align<268435456>) => Some(134217728));
+ test!(#[repr(C, packed(268435456))] (u8; elain::Align<268435456>) => Some(268435456));
+ */
+
+ // Test that `align(N)` does not limit the offset of the trailing field.
+ test!(#[repr(C, align( 1))] (u8; elain::Align< 2>) => Some( 2));
+ test!(#[repr(C, align( 2))] (u8; elain::Align< 4>) => Some( 4));
+ test!(#[repr(C, align( 4))] (u8; elain::Align< 8>) => Some( 8));
+ test!(#[repr(C, align( 8))] (u8; elain::Align< 16>) => Some( 16));
+ test!(#[repr(C, align( 16))] (u8; elain::Align< 32>) => Some( 32));
+ test!(#[repr(C, align( 32))] (u8; elain::Align< 64>) => Some( 64));
+ test!(#[repr(C, align( 64))] (u8; elain::Align< 128>) => Some( 128));
+ test!(#[repr(C, align( 128))] (u8; elain::Align< 256>) => Some( 256));
+ test!(#[repr(C, align( 256))] (u8; elain::Align< 512>) => Some( 512));
+ test!(#[repr(C, align( 512))] (u8; elain::Align< 1024>) => Some( 1024));
+ test!(#[repr(C, align( 1024))] (u8; elain::Align< 2048>) => Some( 2048));
+ test!(#[repr(C, align( 2048))] (u8; elain::Align< 4096>) => Some( 4096));
+ test!(#[repr(C, align( 4096))] (u8; elain::Align< 8192>) => Some( 8192));
+ test!(#[repr(C, align( 8192))] (u8; elain::Align< 16384>) => Some( 16384));
+ test!(#[repr(C, align( 16384))] (u8; elain::Align< 32768>) => Some( 32768));
+ test!(#[repr(C, align( 32768))] (u8; elain::Align< 65536>) => Some( 65536));
+ /* Alignments above 65536 are not yet supported.
+ test!(#[repr(C, align( 65536))] (u8; elain::Align< 131072>) => Some( 131072));
+ test!(#[repr(C, align( 131072))] (u8; elain::Align< 262144>) => Some( 262144));
+ test!(#[repr(C, align( 262144))] (u8; elain::Align< 524288>) => Some( 524288));
+ test!(#[repr(C, align( 524288))] (u8; elain::Align< 1048576>) => Some( 1048576));
+ test!(#[repr(C, align( 1048576))] (u8; elain::Align< 2097152>) => Some( 2097152));
+ test!(#[repr(C, align( 2097152))] (u8; elain::Align< 4194304>) => Some( 4194304));
+ test!(#[repr(C, align( 4194304))] (u8; elain::Align< 8388608>) => Some( 8388608));
+ test!(#[repr(C, align( 8388608))] (u8; elain::Align< 16777216>) => Some( 16777216));
+ test!(#[repr(C, align( 16777216))] (u8; elain::Align< 33554432>) => Some( 33554432));
+ test!(#[repr(C, align( 33554432))] (u8; elain::Align< 67108864>) => Some( 67108864));
+ test!(#[repr(C, align( 67108864))] (u8; elain::Align< 33554432>) => Some( 33554432));
+ test!(#[repr(C, align( 33554432))] (u8; elain::Align<134217728>) => Some(134217728));
+ test!(#[repr(C, align(134217728))] (u8; elain::Align<268435456>) => Some(268435456));
+ */
+ }
+
+ // FIXME(#29), FIXME(https://github.com/rust-lang/rust/issues/69835):
+ // Remove this `cfg` when `size_of_val_raw` is stabilized.
+ #[allow(clippy::decimal_literal_representation)]
+ #[test]
+ fn test_align_of_dst() {
+ // Test that `align_of!` correctly computes the alignment of DSTs.
+ assert_eq!(align_of!([elain::Align<1>]), Some(1));
+ assert_eq!(align_of!([elain::Align<2>]), Some(2));
+ assert_eq!(align_of!([elain::Align<4>]), Some(4));
+ assert_eq!(align_of!([elain::Align<8>]), Some(8));
+ assert_eq!(align_of!([elain::Align<16>]), Some(16));
+ assert_eq!(align_of!([elain::Align<32>]), Some(32));
+ assert_eq!(align_of!([elain::Align<64>]), Some(64));
+ assert_eq!(align_of!([elain::Align<128>]), Some(128));
+ assert_eq!(align_of!([elain::Align<256>]), Some(256));
+ assert_eq!(align_of!([elain::Align<512>]), Some(512));
+ assert_eq!(align_of!([elain::Align<1024>]), Some(1024));
+ assert_eq!(align_of!([elain::Align<2048>]), Some(2048));
+ assert_eq!(align_of!([elain::Align<4096>]), Some(4096));
+ assert_eq!(align_of!([elain::Align<8192>]), Some(8192));
+ assert_eq!(align_of!([elain::Align<16384>]), Some(16384));
+ assert_eq!(align_of!([elain::Align<32768>]), Some(32768));
+ assert_eq!(align_of!([elain::Align<65536>]), Some(65536));
+ /* Alignments above 65536 are not yet supported.
+ assert_eq!(align_of!([elain::Align<131072>]), Some(131072));
+ assert_eq!(align_of!([elain::Align<262144>]), Some(262144));
+ assert_eq!(align_of!([elain::Align<524288>]), Some(524288));
+ assert_eq!(align_of!([elain::Align<1048576>]), Some(1048576));
+ assert_eq!(align_of!([elain::Align<2097152>]), Some(2097152));
+ assert_eq!(align_of!([elain::Align<4194304>]), Some(4194304));
+ assert_eq!(align_of!([elain::Align<8388608>]), Some(8388608));
+ assert_eq!(align_of!([elain::Align<16777216>]), Some(16777216));
+ assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432));
+ assert_eq!(align_of!([elain::Align<67108864>]), Some(67108864));
+ assert_eq!(align_of!([elain::Align<33554432>]), Some(33554432));
+ assert_eq!(align_of!([elain::Align<134217728>]), Some(134217728));
+ assert_eq!(align_of!([elain::Align<268435456>]), Some(268435456));
+ */
+ }
+ }
+
+ #[test]
+ fn test_enum_casts() {
+ // Test that casting the variants of enums with signed integer reprs to
+ // unsigned integers obeys expected signed -> unsigned casting rules.
+
+ #[repr(i8)]
+ enum ReprI8 {
+ MinusOne = -1,
+ Zero = 0,
+ Min = i8::MIN,
+ Max = i8::MAX,
+ }
+
+ #[allow(clippy::as_conversions)]
+ let x = ReprI8::MinusOne as u8;
+ assert_eq!(x, u8::MAX);
+
+ #[allow(clippy::as_conversions)]
+ let x = ReprI8::Zero as u8;
+ assert_eq!(x, 0);
+
+ #[allow(clippy::as_conversions)]
+ let x = ReprI8::Min as u8;
+ assert_eq!(x, 128);
+
+ #[allow(clippy::as_conversions)]
+ let x = ReprI8::Max as u8;
+ assert_eq!(x, 127);
+ }
+
+ #[test]
+ fn test_struct_padding() {
+ // Test that, for each provided repr, `struct_padding!` reports the
+ // expected value.
+ macro_rules! test {
+ (#[$cfg:meta] ($($ts:ty),*) => $expect:expr) => {{
+ #[$cfg]
+ #[allow(dead_code)]
+ struct Test($($ts),*);
+ assert_eq!(struct_padding!(Test, None::<NonZeroUsize>, None::<NonZeroUsize>, [$($ts),*]), $expect);
+ }};
+ (#[$cfg:meta] $(#[$cfgs:meta])* ($($ts:ty),*) => $expect:expr) => {
+ test!(#[$cfg] ($($ts),*) => $expect);
+ test!($(#[$cfgs])* ($($ts),*) => $expect);
+ };
+ }
+
+ test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] () => 0);
+ test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8) => 0);
+ test!(#[repr(C)] #[repr(transparent)] #[repr(packed)] (u8, ()) => 0);
+ test!(#[repr(C)] #[repr(packed)] (u8, u8) => 0);
+
+ test!(#[repr(C)] (u8, AU64) => 7);
+ // Rust won't let you put `#[repr(packed)]` on a type which contains a
+ // `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here.
+ // It's not ideal, but it definitely has align > 1 on /some/ of our CI
+ // targets, and this isn't a particularly complex macro we're testing
+ // anyway.
+ test!(#[repr(packed)] (u8, u64) => 0);
+ }
+
+ #[test]
+ fn test_repr_c_struct_padding() {
+ // Test that, for each provided repr, `repr_c_struct_padding!` reports
+ // the expected value.
+ macro_rules! test {
+ (($($ts:tt),*) => $expect:expr) => {{
+ #[repr(C)]
+ #[allow(dead_code)]
+ struct Test($($ts),*);
+ assert_eq!(repr_c_struct_has_padding!(Test, None::<NonZeroUsize>, None::<NonZeroUsize>, [$($ts),*]), $expect);
+ }};
+ }
+
+ // Test static padding
+ test!(() => false);
+ test!(([u8]) => false);
+ test!((u8) => false);
+ test!((u8, [u8]) => false);
+ test!((u8, ()) => false);
+ test!((u8, (), [u8]) => false);
+ test!((u8, u8) => false);
+ test!((u8, u8, [u8]) => false);
+
+ test!((u8, AU64) => true);
+ test!((u8, AU64, [u8]) => true);
+
+ // Test dynamic padding
+ test!((AU64, [AU64]) => false);
+ test!((u8, [AU64]) => true);
+
+ #[repr(align(4))]
+ struct AU32(#[allow(unused)] u32);
+ test!((AU64, [AU64]) => false);
+ test!((AU64, [AU32]) => true);
+ }
+
+ #[test]
+ fn test_union_padding() {
+ // Test that, for each provided repr, `union_padding!` reports the
+ // expected value.
+ macro_rules! test {
+ (#[$cfg:meta] {$($fs:ident: $ts:ty),*} => $expect:expr) => {{
+ #[$cfg]
+ #[allow(unused)] // fields are never read
+ union Test{ $($fs: $ts),* }
+ assert_eq!(union_padding!(Test, None::<NonZeroUsize>, None::<usize>, [$($ts),*]), $expect);
+ }};
+ (#[$cfg:meta] $(#[$cfgs:meta])* {$($fs:ident: $ts:ty),*} => $expect:expr) => {
+ test!(#[$cfg] {$($fs: $ts),*} => $expect);
+ test!($(#[$cfgs])* {$($fs: $ts),*} => $expect);
+ };
+ }
+
+ test!(#[repr(C)] #[repr(packed)] {a: u8} => 0);
+ test!(#[repr(C)] #[repr(packed)] {a: u8, b: u8} => 0);
+
+ // Rust won't let you put `#[repr(packed)]` on a type which contains a
+ // `#[repr(align(n > 1))]` type (`AU64`), so we have to use `u64` here.
+ // It's not ideal, but it definitely has align > 1 on /some/ of our CI
+ // targets, and this isn't a particularly complex macro we're testing
+ // anyway.
+ test!(#[repr(C)] #[repr(packed)] {a: u8, b: u64} => 7);
+ }
+
+ #[test]
+ fn test_enum_padding() {
+ // Test that, for each provided repr, `enum_has_padding!` reports the
+ // expected value.
+ macro_rules! test {
+ (#[repr($disc:ident $(, $c:ident)?)] { $($vs:ident ($($ts:ty),*),)* } => $expect:expr) => {
+ test!(@case #[repr($disc $(, $c)?)] { $($vs ($($ts),*),)* } => $expect);
+ };
+ (#[repr($disc:ident $(, $c:ident)?)] #[$cfg:meta] $(#[$cfgs:meta])* { $($vs:ident ($($ts:ty),*),)* } => $expect:expr) => {
+ test!(@case #[repr($disc $(, $c)?)] #[$cfg] { $($vs ($($ts),*),)* } => $expect);
+ test!(#[repr($disc $(, $c)?)] $(#[$cfgs])* { $($vs ($($ts),*),)* } => $expect);
+ };
+ (@case #[repr($disc:ident $(, $c:ident)?)] $(#[$cfg:meta])? { $($vs:ident ($($ts:ty),*),)* } => $expect:expr) => {{
+ #[repr($disc $(, $c)?)]
+ $(#[$cfg])?
+ #[allow(unused)] // variants and fields are never used
+ enum Test {
+ $($vs ($($ts),*),)*
+ }
+ assert_eq!(
+ enum_padding!(Test, None::<NonZeroUsize>, None::<NonZeroUsize>, $disc, $([$($ts),*]),*),
+ $expect
+ );
+ }};
+ }
+
+ #[allow(unused)]
+ #[repr(align(2))]
+ struct U16(u16);
+
+ #[allow(unused)]
+ #[repr(align(4))]
+ struct U32(u32);
+
+ test!(#[repr(u8)] #[repr(C)] {
+ A(u8),
+ } => 0);
+ test!(#[repr(u16)] #[repr(C)] {
+ A(u8, u8),
+ B(U16),
+ } => 0);
+ test!(#[repr(u32)] #[repr(C)] {
+ A(u8, u8, u8, u8),
+ B(U16, u8, u8),
+ C(u8, u8, U16),
+ D(U16, U16),
+ E(U32),
+ } => 0);
+
+ // `repr(int)` can pack the discriminant more efficiently
+ test!(#[repr(u8)] {
+ A(u8, U16),
+ } => 0);
+ test!(#[repr(u8)] {
+ A(u8, U16, U32),
+ } => 0);
+
+ // `repr(C)` cannot
+ test!(#[repr(u8, C)] {
+ A(u8, U16),
+ } => 2);
+ test!(#[repr(u8, C)] {
+ A(u8, u8, u8, U32),
+ } => 4);
+
+ // And field ordering can always cause problems
+ test!(#[repr(u8)] #[repr(C)] {
+ A(U16, u8),
+ } => 2);
+ test!(#[repr(u8)] #[repr(C)] {
+ A(U32, u8, u8, u8),
+ } => 4);
+ }
+}
diff --git a/rust/zerocopy/src/util/macros.rs b/rust/zerocopy/src/util/macros.rs
new file mode 100644
index 000000000000..7e63e3a54fc4
--- /dev/null
+++ b/rust/zerocopy/src/util/macros.rs
@@ -0,0 +1,1067 @@
+// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT
+//
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+/// Unsafely implements trait(s) for a type.
+///
+/// # Safety
+///
+/// The trait impl must be sound.
+///
+/// When implementing `TryFromBytes`:
+/// - If no `is_bit_valid` impl is provided, then it must be valid for
+/// `is_bit_valid` to unconditionally return `true`. In other words, it must
+/// be the case that any initialized sequence of bytes constitutes a valid
+/// instance of `$ty`.
+/// - If an `is_bit_valid` impl is provided, then the impl of `is_bit_valid`
+/// must only return `true` if its argument refers to a valid `$ty`.
+macro_rules! unsafe_impl {
+ // Implement `$trait` for `$ty` with no bounds.
+ ($(#[$attr:meta])* $ty:ty: $trait:ident $(; |$candidate:ident| $is_bit_valid:expr)?) => {{
+ crate::util::macros::__unsafe();
+
+ $(#[$attr])*
+ // SAFETY: The caller promises that this is sound.
+ unsafe impl $trait for $ty {
+ unsafe_impl!(@method $trait $(; |$candidate| $is_bit_valid)?);
+ }
+ }};
+
+ // Implement all `$traits` for `$ty` with no bounds.
+ //
+ // The 2 arms under this one are there so we can apply
+ // N attributes for each one of M trait implementations.
+ // The simple solution of:
+ //
+ // ($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => {
+ // $( unsafe_impl!( $(#[$attrs])* $ty: $traits ) );*
+ // }
+ //
+ // Won't work. The macro processor sees that the outer repetition
+ // contains both $attrs and $traits and expects them to match the same
+ // amount of fragments.
+ //
+ // To solve this we must:
+ // 1. Pack the attributes into a single token tree fragment we can match over.
+ // 2. Expand the traits.
+ // 3. Unpack and expand the attributes.
+ ($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => {
+ unsafe_impl!(@impl_traits_with_packed_attrs { $(#[$attrs])* } $ty: $($traits),*)
+ };
+
+ (@impl_traits_with_packed_attrs $attrs:tt $ty:ty: $($traits:ident),*) => {{
+ $( unsafe_impl!(@unpack_attrs $attrs $ty: $traits); )*
+ }};
+
+ (@unpack_attrs { $(#[$attrs:meta])* } $ty:ty: $traits:ident) => {
+ unsafe_impl!($(#[$attrs])* $ty: $traits);
+ };
+
+ // This arm is identical to the following one, except it contains a
+ // preceding `const`. If we attempt to handle these with a single arm, there
+ // is an inherent ambiguity between `const` (the keyword) and `const` (the
+ // ident match for `$tyvar:ident`).
+ //
+ // To explain how this works, consider the following invocation:
+ //
+ // unsafe_impl!(const N: usize, T: ?Sized + Copy => Clone for Foo<T>);
+ //
+ // In this invocation, here are the assignments to meta-variables:
+ //
+ // |---------------|------------|
+ // | Meta-variable | Assignment |
+ // |---------------|------------|
+ // | $constname | N |
+ // | $constty | usize |
+ // | $tyvar | T |
+ // | $optbound | Sized |
+ // | $bound | Copy |
+ // | $trait | Clone |
+ // | $ty | Foo<T> |
+ // |---------------|------------|
+ //
+ // The following arm has the same behavior with the exception of the lack of
+ // support for a leading `const` parameter.
+ (
+ $(#[$attr:meta])*
+ const $constname:ident : $constty:ident $(,)?
+ $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
+ => $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)?
+ ) => {
+ unsafe_impl!(
+ @inner
+ $(#[$attr])*
+ @const $constname: $constty,
+ $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
+ => $trait for $ty $(; |$candidate| $is_bit_valid)?
+ );
+ };
+ (
+ $(#[$attr:meta])*
+ $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
+ => $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)?
+ ) => {{
+ unsafe_impl!(
+ @inner
+ $(#[$attr])*
+ $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
+ => $trait for $ty $(; |$candidate| $is_bit_valid)?
+ );
+ }};
+ (
+ @inner
+ $(#[$attr:meta])*
+ $(@const $constname:ident : $constty:ident,)*
+ $($tyvar:ident $(: $(? $optbound:ident +)* + $($bound:ident +)* )?,)*
+ => $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)?
+ ) => {{
+ crate::util::macros::__unsafe();
+
+ $(#[$attr])*
+ #[allow(non_local_definitions)]
+ // SAFETY: The caller promises that this is sound.
+ unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),* $(, const $constname: $constty,)*> $trait for $ty {
+ unsafe_impl!(@method $trait $(; |$candidate| $is_bit_valid)?);
+ }
+ }};
+
+ (@method TryFromBytes ; |$candidate:ident| $is_bit_valid:expr) => {
+ #[allow(clippy::missing_inline_in_public_items, dead_code)]
+ #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
+ fn only_derive_is_allowed_to_implement_this_trait() {}
+
+ #[inline]
+ fn is_bit_valid<Alignment>($candidate: Maybe<'_, Self, Alignment>) -> bool
+ where
+ Alignment: crate::invariant::Alignment,
+ {
+ $is_bit_valid
+ }
+ };
+ (@method TryFromBytes) => {
+ #[allow(clippy::missing_inline_in_public_items)]
+ #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
+ fn only_derive_is_allowed_to_implement_this_trait() {}
+ #[inline(always)]
+ fn is_bit_valid<Alignment>(_candidate: Maybe<'_, Self, Alignment>) -> bool
+ where
+ Alignment: crate::invariant::Alignment,
+ {
+ true
+ }
+ };
+ (@method $trait:ident) => {
+ #[allow(clippy::missing_inline_in_public_items, dead_code)]
+ #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
+ fn only_derive_is_allowed_to_implement_this_trait() {}
+ };
+ (@method $trait:ident; |$_candidate:ident| $_is_bit_valid:expr) => {
+ compile_error!("Can't provide `is_bit_valid` impl for trait other than `TryFromBytes`");
+ };
+}
+
+/// Implements `$trait` for `$ty` where `$ty: TransmuteFrom<$repr>` (and
+/// vice-versa).
+///
+/// Calling this macro is safe; the internals of the macro emit appropriate
+/// trait bounds which ensure that the given impl is sound.
+macro_rules! impl_for_transmute_from {
+ (
+ $(#[$attr:meta])*
+ $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?)?
+ => $trait:ident for $ty:ty [$repr:ty]
+ ) => {
+ const _: () = {
+ $(#[$attr])*
+ #[allow(non_local_definitions)]
+
+ // SAFETY: `is_trait<T, R>` (defined and used below) requires `T:
+ // TransmuteFrom<R>`, `R: TransmuteFrom<T>`, and `R: $trait`. It is
+ // called using `$ty` and `$repr`, ensuring that `$ty` and `$repr`
+ // have equivalent bit validity, and ensuring that `$repr: $trait`.
+ // The supported traits - `TryFromBytes`, `FromZeros`, `FromBytes`,
+ // and `IntoBytes` - are defined only in terms of the bit validity
+ // of a type. Therefore, `$repr: $trait` ensures that `$ty: $trait`
+ // is sound.
+ unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?> $trait for $ty {
+ #[allow(dead_code, clippy::missing_inline_in_public_items)]
+ #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
+ fn only_derive_is_allowed_to_implement_this_trait() {
+ use crate::pointer::{*, invariant::Valid};
+
+ impl_for_transmute_from!(@assert_is_supported_trait $trait);
+
+ fn is_trait<T, R>()
+ where
+ T: TransmuteFrom<R, Valid, Valid> + ?Sized,
+ R: TransmuteFrom<T, Valid, Valid> + ?Sized,
+ R: $trait,
+ {
+ }
+
+ #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
+ fn f<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?>() {
+ is_trait::<$ty, $repr>();
+ }
+ }
+
+ impl_for_transmute_from!(
+ @is_bit_valid
+ $(<$tyvar $(: $(? $optbound +)* $($bound +)*)?>)?
+ $trait for $ty [$repr]
+ );
+ }
+ };
+ };
+ (@assert_is_supported_trait TryFromBytes) => {};
+ (@assert_is_supported_trait FromZeros) => {};
+ (@assert_is_supported_trait FromBytes) => {};
+ (@assert_is_supported_trait IntoBytes) => {};
+ (
+ @is_bit_valid
+ $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
+ TryFromBytes for $ty:ty [$repr:ty]
+ ) => {
+ #[inline(always)]
+ fn is_bit_valid<Alignment>(candidate: $crate::Maybe<'_, Self, Alignment>) -> bool
+ where
+ Alignment: $crate::invariant::Alignment,
+ {
+ // SAFETY: This macro ensures that `$repr` and `Self` have the same
+ // size and bit validity. Thus, a bit-valid instance of `$repr` is
+ // also a bit-valid instance of `Self`.
+ <$repr as TryFromBytes>::is_bit_valid(candidate.transmute::<_, _, BecauseImmutable>())
+ }
+ };
+ (
+ @is_bit_valid
+ $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
+ $trait:ident for $ty:ty [$repr:ty]
+ ) => {
+ // Trait other than `TryFromBytes`; no `is_bit_valid` impl.
+ };
+}
+
+/// Implements a trait for a type, bounding on each member of the power set of
+/// a set of type variables. This is useful for implementing traits for tuples
+/// or `fn` types.
+///
+/// The last argument is the name of a macro which will be called in every
+/// `impl` block, and is expected to expand to the name of the type for which to
+/// implement the trait.
+///
+/// For example, the invocation:
+/// ```ignore
+/// unsafe_impl_for_power_set!(A, B => Foo for type!(...))
+/// ```
+/// ...expands to:
+/// ```ignore
+/// unsafe impl Foo for type!() { ... }
+/// unsafe impl<B> Foo for type!(B) { ... }
+/// unsafe impl<A, B> Foo for type!(A, B) { ... }
+/// ```
+macro_rules! unsafe_impl_for_power_set {
+ (
+ $first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)
+ $(; |$candidate:ident| $is_bit_valid:expr)?
+ ) => {
+ unsafe_impl_for_power_set!(
+ $($rest),* $(-> $ret)? => $trait for $macro!(...)
+ $(; |$candidate| $is_bit_valid)?
+ );
+ unsafe_impl_for_power_set!(
+ @impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...)
+ $(; |$candidate| $is_bit_valid)?
+ );
+ };
+ (
+ $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)
+ $(; |$candidate:ident| $is_bit_valid:expr)?
+ ) => {
+ unsafe_impl_for_power_set!(
+ @impl $(-> $ret)? => $trait for $macro!(...)
+ $(; |$candidate| $is_bit_valid)?
+ );
+ };
+ (
+ @impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)
+ $(; |$candidate:ident| $is_bit_valid:expr)?
+ ) => {
+ unsafe_impl!(
+ $($vars,)* $($ret)? => $trait for $macro!($($vars),* $(-> $ret)?)
+ $(; |$candidate| $is_bit_valid)?
+ );
+ };
+}
+
+/// Expands to an `Option<extern "C" fn>` type with the given argument types and
+/// return type. Designed for use with `unsafe_impl_for_power_set`.
+macro_rules! opt_extern_c_fn {
+ ($($args:ident),* -> $ret:ident) => { Option<extern "C" fn($($args),*) -> $ret> };
+}
+
+/// Expands to an `Option<unsafe extern "C" fn>` type with the given argument
+/// types and return type. Designed for use with `unsafe_impl_for_power_set`.
+macro_rules! opt_unsafe_extern_c_fn {
+ ($($args:ident),* -> $ret:ident) => { Option<unsafe extern "C" fn($($args),*) -> $ret> };
+}
+
+/// Expands to an `Option<fn>` type with the given argument types and return
+/// type. Designed for use with `unsafe_impl_for_power_set`.
+macro_rules! opt_fn {
+ ($($args:ident),* -> $ret:ident) => { Option<fn($($args),*) -> $ret> };
+}
+
+/// Expands to an `Option<unsafe fn>` type with the given argument types and
+/// return type. Designed for use with `unsafe_impl_for_power_set`.
+macro_rules! opt_unsafe_fn {
+ ($($args:ident),* -> $ret:ident) => { Option<unsafe fn($($args),*) -> $ret> };
+}
+
+// This `allow` is needed because, when testing, we export this macro so it can
+// be used in `doctests`.
+#[allow(rustdoc::private_intra_doc_links)]
+/// Implements trait(s) for a type or verifies the given implementation by
+/// referencing an existing (derived) implementation.
+///
+/// This macro exists so that we can provide zerocopy-derive as an optional
+/// dependency and still get the benefit of using its derives to validate that
+/// our trait impls are sound.
+///
+/// When compiling without `--cfg 'feature = "derive"` and without `--cfg test`,
+/// `impl_or_verify!` emits the provided trait impl. When compiling with either
+/// of those cfgs, it is expected that the type in question is deriving the
+/// traits instead. In this case, `impl_or_verify!` emits code which validates
+/// that the given trait impl is at least as restrictive as the the impl emitted
+/// by the custom derive. This has the effect of confirming that the impl which
+/// is emitted when the `derive` feature is disabled is actually sound (on the
+/// assumption that the impl emitted by the custom derive is sound).
+///
+/// The caller is still required to provide a safety comment (e.g. using the
+/// `const _: () = unsafe` macro). The reason for this restriction is that,
+/// while `impl_or_verify!` can guarantee that the provided impl is sound when
+/// it is compiled with the appropriate cfgs, there is no way to guarantee that
+/// it is ever compiled with those cfgs. In particular, it would be possible to
+/// accidentally place an `impl_or_verify!` call in a context that is only ever
+/// compiled when the `derive` feature is disabled. If that were to happen,
+/// there would be nothing to prevent an unsound trait impl from being emitted.
+/// Requiring a safety comment reduces the likelihood of emitting an unsound
+/// impl in this case, and also provides useful documentation for readers of the
+/// code.
+///
+/// Finally, if a `TryFromBytes::is_bit_valid` impl is provided, it must adhere
+/// to the safety preconditions of [`unsafe_impl!`].
+///
+/// ## Example
+///
+/// ```rust,ignore
+/// // Note that these derives are gated by `feature = "derive"`
+/// #[cfg_attr(any(feature = "derive", test), derive(FromZeros, FromBytes, IntoBytes, Unaligned))]
+/// #[repr(transparent)]
+/// struct Wrapper<T>(T);
+///
+/// const _: () = unsafe {
+/// /// SAFETY:
+/// /// `Wrapper<T>` is `repr(transparent)`, so it is sound to implement any
+/// /// zerocopy trait if `T` implements that trait.
+/// impl_or_verify!(T: FromZeros => FromZeros for Wrapper<T>);
+/// impl_or_verify!(T: FromBytes => FromBytes for Wrapper<T>);
+/// impl_or_verify!(T: IntoBytes => IntoBytes for Wrapper<T>);
+/// impl_or_verify!(T: Unaligned => Unaligned for Wrapper<T>);
+/// }
+/// ```
+#[cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_DEV_MODE, macro_export)] // Used in `doctests.rs`
+#[doc(hidden)]
+macro_rules! impl_or_verify {
+ // The following two match arms follow the same pattern as their
+ // counterparts in `unsafe_impl!`; see the documentation on those arms for
+ // more details.
+ (
+ const $constname:ident : $constty:ident $(,)?
+ $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
+ => $trait:ident for $ty:ty
+ ) => {
+ impl_or_verify!(@impl { unsafe_impl!(
+ const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
+ ); });
+ impl_or_verify!(@verify $trait, {
+ impl<const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
+ });
+ };
+ (
+ $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
+ => $trait:ident for $ty:ty $(; |$candidate:ident| $is_bit_valid:expr)?
+ ) => {
+ impl_or_verify!(@impl { unsafe_impl!(
+ $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
+ $(; |$candidate| $is_bit_valid)?
+ ); });
+ impl_or_verify!(@verify $trait, {
+ impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
+ });
+ };
+ (@impl $impl_block:tt) => {
+ #[cfg(not(any(feature = "derive", test)))]
+ { $impl_block };
+ };
+ (@verify $trait:ident, $impl_block:tt) => {
+ #[cfg(any(feature = "derive", test))]
+ {
+ // On some toolchains, `Subtrait` triggers the `dead_code` lint
+ // because it is implemented but never used.
+ #[allow(dead_code)]
+ trait Subtrait: $trait {}
+ $impl_block
+ };
+ };
+}
+
+/// Implements `KnownLayout` for a sized type.
+macro_rules! impl_known_layout {
+ ($(const $constvar:ident : $constty:ty, $tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
+ $(impl_known_layout!(@inner const $constvar: $constty, $tyvar $(: ?$optbound)? => $ty);)*
+ };
+ ($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
+ $(impl_known_layout!(@inner , $tyvar $(: ?$optbound)? => $ty);)*
+ };
+ ($($(#[$attrs:meta])* $ty:ty),*) => { $(impl_known_layout!(@inner , => $(#[$attrs])* $ty);)* };
+ (@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $(#[$attrs:meta])* $ty:ty) => {
+ const _: () = {
+ use core::ptr::NonNull;
+
+ #[allow(non_local_definitions)]
+ $(#[$attrs])*
+ // SAFETY: Delegates safety to `DstLayout::for_type`.
+ unsafe impl<$($tyvar $(: ?$optbound)?)? $(, const $constvar : $constty)?> KnownLayout for $ty {
+ #[allow(clippy::missing_inline_in_public_items)]
+ #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
+ fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {}
+
+ type PointerMetadata = ();
+
+ // SAFETY: `CoreMaybeUninit<T>::LAYOUT` and `T::LAYOUT` are
+ // identical because `CoreMaybeUninit<T>` has the same size and
+ // alignment as `T` [1], and `CoreMaybeUninit` admits
+ // uninitialized bytes in all positions.
+ //
+ // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1:
+ //
+ // `MaybeUninit<T>` is guaranteed to have the same size,
+ // alignment, and ABI as `T`
+ type MaybeUninit = core::mem::MaybeUninit<Self>;
+
+ const LAYOUT: crate::DstLayout = crate::DstLayout::for_type::<$ty>();
+
+ // SAFETY: `.cast` preserves address and provenance.
+ //
+ // FIXME(#429): Add documentation to `.cast` that promises that
+ // it preserves provenance.
+ #[inline(always)]
+ fn raw_from_ptr_len(bytes: NonNull<u8>, _meta: ()) -> NonNull<Self> {
+ bytes.cast::<Self>()
+ }
+
+ #[inline(always)]
+ fn pointer_to_metadata(_ptr: *mut Self) -> () {
+ }
+ }
+ };
+ };
+}
+
+/// Implements `KnownLayout` for a type in terms of the implementation of
+/// another type with the same representation.
+///
+/// # Safety
+///
+/// - `$ty` and `$repr` must have the same:
+/// - Fixed prefix size
+/// - Alignment
+/// - (For DSTs) trailing slice element size
+/// - It must be valid to perform an `as` cast from `*mut $repr` to `*mut $ty`,
+/// and this operation must preserve referent size (ie, `size_of_val_raw`).
+macro_rules! unsafe_impl_known_layout {
+ ($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => {{
+ use core::ptr::NonNull;
+
+ crate::util::macros::__unsafe();
+
+ #[allow(non_local_definitions)]
+ // SAFETY: The caller promises that this is sound.
+ unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty {
+ #[allow(clippy::missing_inline_in_public_items, dead_code)]
+ #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))]
+ fn only_derive_is_allowed_to_implement_this_trait() {}
+
+ type PointerMetadata = <$repr as KnownLayout>::PointerMetadata;
+ type MaybeUninit = <$repr as KnownLayout>::MaybeUninit;
+
+ const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;
+
+ // SAFETY: All operations preserve address and provenance. Caller
+ // has promised that the `as` cast preserves size.
+ //
+ // FIXME(#429): Add documentation to `NonNull::new_unchecked` that
+ // it preserves provenance.
+ #[inline(always)]
+ fn raw_from_ptr_len(bytes: NonNull<u8>, meta: <$repr as KnownLayout>::PointerMetadata) -> NonNull<Self> {
+ #[allow(clippy::as_conversions)]
+ let ptr = <$repr>::raw_from_ptr_len(bytes, meta).as_ptr() as *mut Self;
+ // SAFETY: `ptr` was converted from `bytes`, which is non-null.
+ unsafe { NonNull::new_unchecked(ptr) }
+ }
+
+ #[inline(always)]
+ fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata {
+ #[allow(clippy::as_conversions)]
+ let ptr = ptr as *mut $repr;
+ <$repr>::pointer_to_metadata(ptr)
+ }
+ }
+ }};
+}
+
+/// Uses `align_of` to confirm that a type or set of types have alignment 1.
+///
+/// Note that `align_of<T>` requires `T: Sized`, so this macro doesn't work for
+/// unsized types.
+macro_rules! assert_unaligned {
+ ($($tys: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::<$tys>(), 1);
+ )*
+ };
+}
+
+/// Emits a function definition as either `const fn` or `fn` depending on
+/// whether the current toolchain version supports `const fn` with generic trait
+/// bounds.
+macro_rules! maybe_const_trait_bounded_fn {
+ // This case handles both `self` methods (where `self` is by value) and
+ // non-method functions. Each `$args` may optionally be followed by `:
+ // $arg_tys:ty`, which can be omitted for `self`.
+ ($(#[$attr:meta])* $vis:vis const fn $name:ident($($args:ident $(: $arg_tys:ty)?),* $(,)?) $(-> $ret_ty:ty)? $body:block) => {
+ #[cfg(not(no_zerocopy_generic_bounds_in_const_fn_1_61_0))]
+ $(#[$attr])* $vis const fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body
+
+ #[cfg(no_zerocopy_generic_bounds_in_const_fn_1_61_0)]
+ $(#[$attr])* $vis fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body
+ };
+}
+
+/// Either panic (if the current Rust toolchain supports panicking in `const
+/// fn`) or evaluate a constant that will cause an array indexing error whose
+/// error message will include the format string.
+///
+/// The type that this expression evaluates to must be `Copy`, or else the
+/// non-panicking desugaring will fail to compile.
+macro_rules! const_panic {
+ (@non_panic $($_arg:tt)+) => {{
+ // This will type check to whatever type is expected based on the call
+ // site.
+ let panic: [_; 0] = [];
+ // This will always fail (since we're indexing into an array of size 0.
+ #[allow(unconditional_panic)]
+ panic[0]
+ }};
+ ($($arg:tt)+) => {{
+ #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
+ panic!($($arg)+);
+ #[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
+ const_panic!(@non_panic $($arg)+)
+ }};
+}
+
+/// Either assert (if the current Rust toolchain supports panicking in `const
+/// fn`) or evaluate the expression and, if it evaluates to `false`, call
+/// `const_panic!`. This is used in place of `assert!` in const contexts to
+/// accommodate old toolchains.
+macro_rules! const_assert {
+ ($e:expr) => {{
+ #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
+ assert!($e);
+ #[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
+ {
+ let e = $e;
+ if !e {
+ let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e)));
+ }
+ }
+ }};
+ ($e:expr, $($args:tt)+) => {{
+ #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
+ assert!($e, $($args)+);
+ #[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
+ {
+ let e = $e;
+ if !e {
+ let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e), ": ", stringify!($arg)), $($args)*);
+ }
+ }
+ }};
+}
+
+/// Like `const_assert!`, but relative to `debug_assert!`.
+macro_rules! const_debug_assert {
+ ($e:expr $(, $msg:expr)?) => {{
+ #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
+ debug_assert!($e $(, $msg)?);
+ #[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
+ {
+ // Use this (rather than `#[cfg(debug_assertions)]`) to ensure that
+ // `$e` is always compiled even if it will never be evaluated at
+ // runtime.
+ if cfg!(debug_assertions) {
+ let e = $e;
+ if !e {
+ let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e) $(, ": ", $msg)?));
+ }
+ }
+ }
+ }}
+}
+
+/// Either invoke `unreachable!()` or `loop {}` depending on whether the Rust
+/// toolchain supports panicking in `const fn`.
+macro_rules! const_unreachable {
+ () => {{
+ #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
+ unreachable!();
+
+ #[cfg(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)]
+ loop {}
+ }};
+}
+
+/// Asserts at compile time that `$condition` is true for `Self` or the given
+/// `$tyvar`s. Unlike `const_assert`, this is *strictly* a compile-time check;
+/// it cannot be evaluated in a runtime context. The condition is checked after
+/// monomorphization and, upon failure, emits a compile error.
+macro_rules! static_assert {
+ (Self $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )? => $condition:expr $(, $args:tt)*) => {{
+ trait StaticAssert {
+ const ASSERT: bool;
+ }
+
+ impl<T $(: $(? $optbound +)* $($bound +)*)?> StaticAssert for T {
+ const ASSERT: bool = {
+ const_assert!($condition $(, $args)*);
+ $condition
+ };
+ }
+
+ const_assert!(<Self as StaticAssert>::ASSERT);
+ }};
+ ($($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $condition:expr $(, $args:tt)*) => {{
+ trait StaticAssert {
+ const ASSERT: bool;
+ }
+
+ // NOTE: We use `PhantomData` so we can support unsized types.
+ impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?,)*> StaticAssert for ($(core::marker::PhantomData<$tyvar>,)*) {
+ const ASSERT: bool = {
+ const_assert!($condition $(, $args)*);
+ $condition
+ };
+ }
+
+ const_assert!(<($(core::marker::PhantomData<$tyvar>,)*) as StaticAssert>::ASSERT);
+ }};
+}
+
+/// Assert at compile time that `tyvar` does not have a zero-sized DST
+/// component.
+macro_rules! static_assert_dst_is_not_zst {
+ ($tyvar:ident) => {{
+ use crate::KnownLayout;
+ static_assert!($tyvar: ?Sized + KnownLayout => {
+ let dst_is_zst = match $tyvar::LAYOUT.size_info {
+ crate::SizeInfo::Sized { .. } => false,
+ crate::SizeInfo::SliceDst(TrailingSliceLayout { elem_size, .. }) => {
+ elem_size == 0
+ }
+ };
+ !dst_is_zst
+ }, "cannot call this method on a dynamically-sized type whose trailing slice element is zero-sized");
+ }}
+}
+
+/// Defines a named [`Cast`] implementation.
+///
+/// # Safety
+///
+/// The caller must ensure that, given `src: *mut $src`, `src as *mut $dst` is a
+/// size-preserving or size-shrinking cast.
+///
+/// [`Cast`]: crate::pointer::cast::Cast
+#[macro_export]
+#[doc(hidden)]
+macro_rules! define_cast {
+ // We require the caller to provide an `unsafe` block as part of the input
+ // syntax since a call to `define_cast!` is useless inside of an `unsafe`
+ // block (since it would introduce a type which can't be named outside of
+ // the context of that block).
+ (unsafe { $vis:vis $name:ident $(<$tyvar:ident $(: ?$optbound:ident)?>)? = $src:ty => $dst:ty }) => {
+ #[allow(missing_debug_implementations, missing_copy_implementations, unreachable_pub)]
+ $vis enum $name {}
+
+ // SAFETY: The caller promises that `src as *mut $src` is a size-
+ // preserving or size-shrinking cast. All operations preserve
+ // provenance.
+ unsafe impl $(<$tyvar $(: ?$optbound)?>)? $crate::pointer::cast::Project<$src, $dst> for $name {
+ fn project(src: $crate::pointer::PtrInner<'_, $src>) -> *mut $dst {
+ #[allow(clippy::as_conversions)]
+ return src.as_ptr() as *mut $dst;
+ }
+ }
+
+ // SAFETY: The impl of `Project::project` preserves referent address.
+ unsafe impl $(<$tyvar $(: ?$optbound)?>)? $crate::pointer::cast::Cast<$src, $dst> for $name {}
+ };
+}
+
+/// Implements `TransmuteFrom` and `SizeEq` for `T` and `$wrapper<T>`.
+///
+/// # Safety
+///
+/// `T` and `$wrapper<T>` must have the same bit validity, and must have the
+/// same size in the sense of `CastExact` (specifically, both a
+/// `T`-to-`$wrapper<T>` cast and a `$wrapper<T>`-to-`T` cast must be
+/// size-preserving).
+macro_rules! unsafe_impl_for_transparent_wrapper {
+ ($vis:vis T $(: ?$optbound:ident)? => $wrapper:ident<T>) => {{
+ crate::util::macros::__unsafe();
+
+ use crate::pointer::{TransmuteFrom, cast::{CastExact, TransitiveProject}, SizeEq, invariant::Valid};
+ use crate::wrappers::ReadOnly;
+
+ // SAFETY: The caller promises that `T` and `$wrapper<T>` have the same
+ // bit validity.
+ unsafe impl<T $(: ?$optbound)?> TransmuteFrom<T, Valid, Valid> for $wrapper<T> {}
+ // SAFETY: See previous safety comment.
+ unsafe impl<T $(: ?$optbound)?> TransmuteFrom<$wrapper<T>, Valid, Valid> for T {}
+ // SAFETY: The caller promises that a `T` to `$wrapper<T>` cast is
+ // size-preserving.
+ define_cast!(unsafe { $vis CastToWrapper<T $(: ?$optbound)? > = T => $wrapper<T> });
+ // SAFETY: The caller promises that a `T` to `$wrapper<T>` cast is
+ // size-preserving.
+ unsafe impl<T $(: ?$optbound)?> CastExact<T, $wrapper<T>> for CastToWrapper {}
+ // SAFETY: The caller promises that a `$wrapper<T>` to `T` cast is
+ // size-preserving.
+ define_cast!(unsafe { $vis CastFromWrapper<T $(: ?$optbound)? > = $wrapper<T> => T });
+ // SAFETY: The caller promises that a `$wrapper<T>` to `T` cast is
+ // size-preserving.
+ unsafe impl<T $(: ?$optbound)?> CastExact<$wrapper<T>, T> for CastFromWrapper {}
+
+ impl<T $(: ?$optbound)?> SizeEq<T> for $wrapper<T> {
+ type CastFrom = CastToWrapper;
+ }
+ impl<T $(: ?$optbound)?> SizeEq<$wrapper<T>> for T {
+ type CastFrom = CastFromWrapper;
+ }
+
+ impl<T $(: ?$optbound)?> SizeEq<ReadOnly<T>> for $wrapper<T> {
+ type CastFrom = TransitiveProject<
+ T,
+ <T as SizeEq<ReadOnly<T>>>::CastFrom,
+ CastToWrapper,
+ >;
+ }
+ impl<T $(: ?$optbound)?> SizeEq<$wrapper<T>> for ReadOnly<T> {
+ type CastFrom = TransitiveProject<
+ T,
+ CastFromWrapper,
+ <ReadOnly<T> as SizeEq<T>>::CastFrom,
+ >;
+ }
+
+ impl<T $(: ?$optbound)?> SizeEq<ReadOnly<T>> for ReadOnly<$wrapper<T>> {
+ type CastFrom = TransitiveProject<
+ $wrapper<T>,
+ <$wrapper<T> as SizeEq<ReadOnly<T>>>::CastFrom,
+ <ReadOnly<$wrapper<T>> as SizeEq<$wrapper<T>>>::CastFrom,
+ >;
+ }
+ impl<T $(: ?$optbound)?> SizeEq<ReadOnly<$wrapper<T>>> for ReadOnly<T> {
+ type CastFrom = TransitiveProject<
+ $wrapper<T>,
+ <$wrapper<T> as SizeEq<ReadOnly<$wrapper<T>>>>::CastFrom,
+ <ReadOnly<T> as SizeEq<$wrapper<T>>>::CastFrom,
+ >;
+ }
+ }};
+}
+
+macro_rules! impl_transitive_transmute_from {
+ ($($tyvar:ident $(: ?$optbound:ident)?)? => $t:ty => $u:ty => $v:ty) => {
+ const _: () = {
+ use crate::pointer::{TransmuteFrom, SizeEq, invariant::Valid};
+
+ impl<$($tyvar $(: ?$optbound)?)?> SizeEq<$t> for $v
+ where
+ $u: SizeEq<$t>,
+ $v: SizeEq<$u>,
+ {
+ type CastFrom = cast::TransitiveProject<
+ $u,
+ <$u as SizeEq<$t>>::CastFrom,
+ <$v as SizeEq<$u>>::CastFrom
+ >;
+ }
+
+ // SAFETY: Since `$u: TransmuteFrom<$t, Valid, Valid>`, it is sound
+ // to transmute a bit-valid `$t` to a bit-valid `$u`. Since `$v:
+ // TransmuteFrom<$u, Valid, Valid>`, it is sound to transmute that
+ // bit-valid `$u` to a bit-valid `$v`.
+ unsafe impl<$($tyvar $(: ?$optbound)?)?> TransmuteFrom<$t, Valid, Valid> for $v
+ where
+ $u: TransmuteFrom<$t, Valid, Valid>,
+ $v: TransmuteFrom<$u, Valid, Valid>,
+ {}
+ };
+ };
+}
+
+/// A no-op `unsafe fn` for use in macro expansions.
+///
+/// Calling this function in a macro expansion ensures that the macro's caller
+/// must wrap the call in `unsafe { ... }`.
+#[inline(always)]
+pub(crate) const unsafe fn __unsafe() {}
+
+/// Extracts the contents of doc comments.
+#[allow(unused)]
+macro_rules! docstring {
+ ($(#[doc = $content:expr])*) => {
+ concat!($($content, "\n",)*)
+ }
+}
+
+/// Generate a rustdoc-style header with `$name` as the HTML ID for the 'Code
+/// Generation' section of documentation.
+#[allow(unused)]
+macro_rules! codegen_header {
+ ($level:expr, $name:expr) => {
+ concat!(
+ "
+<",
+ $level,
+ " id='method.",
+ $name,
+ ".codegen'>
+ <a class='doc-anchor' href='#method.",
+ $name,
+ ".codegen'>§</a>
+ Code Generation
+</",
+ $level,
+ ">
+"
+ )
+ };
+}
+
+/// Generates HTML tabs.
+#[rustfmt::skip]
+#[allow(unused)]
+macro_rules! tabs {
+ (
+ name = $name:expr,
+ arity = $arity:literal,
+ $([
+ $($open:ident)?
+ @index $n:literal
+ @title $title:literal
+ $(#[doc = $content:expr])*
+ ]),*
+ ) => {
+ concat!("
+<div class='codegen-tabs' style='--arity: ", $arity ,"'>", $(concat!("
+ <details name='tab-", $name,"' style='--n: ", $n ,"'", $(stringify!($open),)*">
+ <summary><h6>", $title, "</h6></summary>
+ <div>
+
+", $($content, "\n",)* "
+\
+ </div>
+ </details>"),)*
+"</div>")
+ }
+}
+
+/// Generates the HTML for a single benchmark example.
+#[allow(unused)]
+macro_rules! codegen_example {
+ (format = $format:expr, bench = $bench:expr) => {
+ tabs!(
+ name = $bench,
+ arity = 4,
+ [
+ @index 1
+ @title "Format"
+ /// ```ignore
+ #[doc = include_str!(concat!("../benches/formats/", $format, ".rs"))]
+ /// ```
+ ],
+ [
+ @index 2
+ @title "Benchmark"
+ /// ```ignore
+ #[doc = include_str!(concat!("../benches/", $bench, ".rs"))]
+ /// ```
+ ],
+ [
+ open
+ @index 3
+ @title "Assembly"
+ /// ```plain
+ #[doc = include_str!(concat!("../benches/", $bench, ".x86-64"))]
+ /// ```
+ ],
+ [
+ @index 4
+ @title "Machine Code Analysis"
+ /// ```plain
+ #[doc = include_str!(concat!("../benches/", $bench, ".x86-64.mca"))]
+ /// ```
+ ]
+ )
+ }
+}
+
+/// Generate the HTML for a suite of benchmark examples.
+#[allow(unused)]
+macro_rules! codegen_example_suite {
+ (
+ bench = $bench:expr,
+ format = $format:expr,
+ arity = $arity:literal,
+ $([
+ $($open:ident)?
+ @index $index:literal
+ @title $title:literal
+ @variant $variant:literal
+ ]),*
+ ) => {
+ tabs!(
+ name = $bench,
+ arity = $arity,
+ $([
+ $($open)*
+ @index $index
+ @title $title
+ #[doc = codegen_example!(
+ format = concat!($format, "_", $variant),
+ bench = concat!($bench, "_", $variant)
+ )]
+ ]),*
+ )
+ }
+}
+
+/// Generates the string for code generation preamble.
+#[allow(unused)]
+macro_rules! codegen_preamble {
+ () => {
+ docstring!(
+ ///
+ /// This abstraction is safe and cheap, but does not necessarily
+ /// have zero runtime cost. The codegen you experience in practice
+ /// will depend on optimization level, the layout of the destination
+ /// type, and what the compiler can prove about the source.
+ ///
+ )
+ }
+}
+
+/// Stub for rendering codegen documentation; used to break build dependency
+/// between benches and zerocopy when re-blessing codegen tests.
+#[allow(unused)]
+#[cfg(not(doc))]
+macro_rules! codegen_section {
+ (
+ header = $level:expr,
+ bench = $bench:expr,
+ format = $format:expr,
+ arity = $arity:literal,
+ $([
+ $($open:ident)?
+ @index $index:literal
+ @title $title:literal
+ @variant $variant:literal
+ ]),*
+ ) => {
+ ""
+ };
+ (
+ header = $level:expr,
+ bench = $bench:expr,
+ format = $format:expr,
+ ) => {
+ ""
+ };
+}
+
+/// Generates the HTML for code generation documentation.
+#[allow(unused)]
+#[cfg(doc)]
+macro_rules! codegen_section {
+ (
+ header = $level:expr,
+ bench = $bench:expr,
+ format = $format:expr,
+ arity = $arity:literal,
+ $([
+ $($open:ident)?
+ @index $index:literal
+ @title $title:literal
+ @variant $variant:literal
+ ]),*
+ ) => {
+ concat!(
+ codegen_header!($level, $bench),
+ codegen_preamble!(),
+ docstring!(
+ ///
+ /// The below examples illustrate typical codegen for
+ /// increasingly complex types:
+ ///
+ ),
+ codegen_example_suite!(
+ bench = $bench,
+ format = $format,
+ arity = $arity,
+ $([
+ $($open)*
+ @index $index
+ @title $title
+ @variant $variant
+ ]),*
+ )
+ )
+ };
+ (
+ header = $level:expr,
+ bench = $bench:expr,
+ format = $format:expr,
+ ) => {
+ concat!(
+ codegen_header!($level, $bench),
+ codegen_preamble!(),
+ codegen_example!(
+ format = $format,
+ bench = $bench
+ )
+ )
+ }
+}
diff --git a/rust/zerocopy/src/util/mod.rs b/rust/zerocopy/src/util/mod.rs
new file mode 100644
index 000000000000..02fd4ed62741
--- /dev/null
+++ b/rust/zerocopy/src/util/mod.rs
@@ -0,0 +1,944 @@
+// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT
+//
+// Copyright 2023 The Fuchsia Authors
+//
+// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
+// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
+// This file may not be copied, modified, or distributed except according to
+// those terms.
+
+#[macro_use]
+pub(crate) mod macros;
+
+#[doc(hidden)]
+pub mod macro_util;
+
+use core::{
+ marker::PhantomData,
+ mem::{self, ManuallyDrop},
+ num::NonZeroUsize,
+ ptr::NonNull,
+};
+
+use super::*;
+use crate::pointer::{
+ invariant::{Exclusive, Shared, Valid},
+ SizeEq, TransmuteFromPtr,
+};
+
+/// Like [`PhantomData`], but [`Send`] and [`Sync`] regardless of whether the
+/// wrapped `T` is.
+pub(crate) struct SendSyncPhantomData<T: ?Sized>(PhantomData<T>);
+
+// SAFETY: `SendSyncPhantomData` does not enable any behavior which isn't sound
+// to be called from multiple threads.
+unsafe impl<T: ?Sized> Send for SendSyncPhantomData<T> {}
+// SAFETY: `SendSyncPhantomData` does not enable any behavior which isn't sound
+// to be called from multiple threads.
+unsafe impl<T: ?Sized> Sync for SendSyncPhantomData<T> {}
+
+impl<T: ?Sized> Default for SendSyncPhantomData<T> {
+ fn default() -> SendSyncPhantomData<T> {
+ SendSyncPhantomData(PhantomData)
+ }
+}
+
+impl<T: ?Sized> PartialEq for SendSyncPhantomData<T> {
+ fn eq(&self, _other: &Self) -> bool {
+ true
+ }
+}
+
+impl<T: ?Sized> Eq for SendSyncPhantomData<T> {}
+
+impl<T: ?Sized> Clone for SendSyncPhantomData<T> {
+ fn clone(&self) -> Self {
+ SendSyncPhantomData(PhantomData)
+ }
+}
+
+#[cfg(miri)]
+extern "Rust" {
+ /// Miri-provided intrinsic that marks the pointer `ptr` as aligned to
+ /// `align`.
+ ///
+ /// This intrinsic is used to inform Miri's symbolic alignment checker that
+ /// a pointer is aligned, even if Miri cannot statically deduce that fact.
+ /// This is often required when performing raw pointer arithmetic or casts
+ /// where the alignment is guaranteed by runtime checks or invariants that
+ /// Miri is not aware of.
+ pub(crate) fn miri_promise_symbolic_alignment(ptr: *const (), align: usize);
+}
+
+pub(crate) trait AsAddress {
+ fn addr(self) -> usize;
+}
+
+impl<T: ?Sized> AsAddress for &T {
+ #[inline(always)]
+ fn addr(self) -> usize {
+ let ptr: *const T = self;
+ AsAddress::addr(ptr)
+ }
+}
+
+impl<T: ?Sized> AsAddress for &mut T {
+ #[inline(always)]
+ fn addr(self) -> usize {
+ let ptr: *const T = self;
+ AsAddress::addr(ptr)
+ }
+}
+
+impl<T: ?Sized> AsAddress for NonNull<T> {
+ #[inline(always)]
+ fn addr(self) -> usize {
+ AsAddress::addr(self.as_ptr())
+ }
+}
+
+impl<T: ?Sized> AsAddress for *const T {
+ #[inline(always)]
+ fn addr(self) -> usize {
+ // FIXME(#181), FIXME(https://github.com/rust-lang/rust/issues/95228):
+ // Use `.addr()` instead of `as usize` once it's stable, and get rid of
+ // this `allow`. Currently, `as usize` is the only way to accomplish
+ // this.
+ #[allow(clippy::as_conversions)]
+ #[cfg_attr(
+ __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS,
+ allow(lossy_provenance_casts)
+ )]
+ return self.cast::<()>() as usize;
+ }
+}
+
+impl<T: ?Sized> AsAddress for *mut T {
+ #[inline(always)]
+ fn addr(self) -> usize {
+ let ptr: *const T = self;
+ AsAddress::addr(ptr)
+ }
+}
+
+/// Validates that `t` is aligned to `align_of::<U>()`.
+#[inline(always)]
+pub(crate) fn validate_aligned_to<T: AsAddress, U>(t: T) -> Result<(), AlignmentError<(), U>> {
+ // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
+ // turn guarantees that this mod operation will not panic.
+ #[allow(clippy::arithmetic_side_effects)]
+ let remainder = t.addr() % mem::align_of::<U>();
+ if remainder == 0 {
+ Ok(())
+ } else {
+ // SAFETY: We just confirmed that `t.addr() % align_of::<U>() != 0`.
+ // That's only possible if `align_of::<U>() > 1`.
+ Err(unsafe { AlignmentError::new_unchecked(()) })
+ }
+}
+
+/// Returns the bytes needed to pad `len` to the next multiple of `align`.
+///
+/// This function assumes that align is a power of two; there are no guarantees
+/// on the answer it gives if this is not the case.
+#[cfg_attr(
+ kani,
+ kani::requires(len <= DstLayout::MAX_SIZE),
+ kani::requires(align.is_power_of_two()),
+ kani::ensures(|&p| (len + p) % align.get() == 0),
+ // Ensures that we add the minimum required padding.
+ kani::ensures(|&p| p < align.get()),
+)]
+#[cfg_attr(not(zerocopy_inline_always), inline)]
+#[cfg_attr(zerocopy_inline_always, inline(always))]
+pub(crate) const fn padding_needed_for(len: usize, align: NonZeroUsize) -> usize {
+ #[cfg(kani)]
+ #[kani::proof_for_contract(padding_needed_for)]
+ fn proof() {
+ padding_needed_for(kani::any(), kani::any());
+ }
+
+ // Abstractly, we want to compute:
+ // align - (len % align).
+ // Handling the case where len%align is 0.
+ // Because align is a power of two, len % align = len & (align-1).
+ // Guaranteed not to underflow as align is nonzero.
+ #[allow(clippy::arithmetic_side_effects)]
+ let mask = align.get() - 1;
+
+ // To efficiently subtract this value from align, we can use the bitwise
+ // complement.
+ // Note that ((!len) & (align-1)) gives us a number that with (len &
+ // (align-1)) sums to align-1. So subtracting 1 from x before taking the
+ // complement subtracts `len` from `align`. Some quick inspection of
+ // cases shows that this also handles the case where `len % align = 0`
+ // correctly too: len-1 % align then equals align-1, so the complement mod
+ // align will be 0, as desired.
+ //
+ // The following reasoning can be verified quickly by an SMT solver
+ // supporting the theory of bitvectors:
+ // ```smtlib
+ // ; Naive implementation of padding
+ // (define-fun padding1 (
+ // (len (_ BitVec 32))
+ // (align (_ BitVec 32))) (_ BitVec 32)
+ // (ite
+ // (= (_ bv0 32) (bvand len (bvsub align (_ bv1 32))))
+ // (_ bv0 32)
+ // (bvsub align (bvand len (bvsub align (_ bv1 32))))))
+ //
+ // ; The implementation below
+ // (define-fun padding2 (
+ // (len (_ BitVec 32))
+ // (align (_ BitVec 32))) (_ BitVec 32)
+ // (bvand (bvnot (bvsub len (_ bv1 32))) (bvsub align (_ bv1 32))))
+ //
+ // (define-fun is-power-of-two ((x (_ BitVec 32))) Bool
+ // (= (_ bv0 32) (bvand x (bvsub x (_ bv1 32)))))
+ //
+ // (declare-const len (_ BitVec 32))
+ // (declare-const align (_ BitVec 32))
+ // ; Search for a case where align is a power of two and padding2 disagrees
+ // ; with padding1
+ // (assert (and (is-power-of-two align)
+ // (not (= (padding1 len align) (padding2 len align)))))
+ // (simplify (padding1 (_ bv300 32) (_ bv32 32))) ; 20
+ // (simplify (padding2 (_ bv300 32) (_ bv32 32))) ; 20
+ // (simplify (padding1 (_ bv322 32) (_ bv32 32))) ; 30
+ // (simplify (padding2 (_ bv322 32) (_ bv32 32))) ; 30
+ // (simplify (padding1 (_ bv8 32) (_ bv8 32))) ; 0
+ // (simplify (padding2 (_ bv8 32) (_ bv8 32))) ; 0
+ // (check-sat) ; unsat, also works for 64-bit bitvectors
+ // ```
+ !(len.wrapping_sub(1)) & mask
+}
+
+/// Rounds `n` down to the largest value `m` such that `m <= n` and `m % align
+/// == 0`.
+///
+/// # Panics
+///
+/// May panic if `align` is not a power of two. Even if it doesn't panic in this
+/// case, it will produce nonsense results.
+#[inline(always)]
+#[cfg_attr(
+ kani,
+ kani::requires(align.is_power_of_two()),
+ kani::ensures(|&m| m <= n && m % align.get() == 0),
+ // Guarantees that `m` is the *largest* value such that `m % align == 0`.
+ kani::ensures(|&m| {
+ // If this `checked_add` fails, then the next multiple would wrap
+ // around, which trivially satisfies the "largest value" requirement.
+ m.checked_add(align.get()).map(|next_mul| next_mul > n).unwrap_or(true)
+ })
+)]
+pub(crate) const fn round_down_to_next_multiple_of_alignment(
+ n: usize,
+ align: NonZeroUsize,
+) -> usize {
+ #[cfg(kani)]
+ #[kani::proof_for_contract(round_down_to_next_multiple_of_alignment)]
+ fn proof() {
+ round_down_to_next_multiple_of_alignment(kani::any(), kani::any());
+ }
+
+ let align = align.get();
+ #[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
+ debug_assert!(align.is_power_of_two());
+
+ // Subtraction can't underflow because `align.get() >= 1`.
+ #[allow(clippy::arithmetic_side_effects)]
+ let mask = !(align - 1);
+ n & mask
+}
+
+#[cfg_attr(not(zerocopy_inline_always), inline)]
+#[cfg_attr(zerocopy_inline_always, inline(always))]
+pub(crate) const fn max(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
+ if a.get() < b.get() {
+ b
+ } else {
+ a
+ }
+}
+
+#[cfg_attr(not(zerocopy_inline_always), inline)]
+#[cfg_attr(zerocopy_inline_always, inline(always))]
+pub(crate) const fn min(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
+ if a.get() > b.get() {
+ b
+ } else {
+ a
+ }
+}
+
+/// Copies `src` into the prefix of `dst`.
+///
+/// # Safety
+///
+/// The caller guarantees that `src.len() <= dst.len()`.
+#[inline(always)]
+pub(crate) unsafe fn copy_unchecked(src: &[u8], dst: &mut [u8]) {
+ debug_assert!(src.len() <= dst.len());
+ // SAFETY: This invocation satisfies the safety contract of
+ // copy_nonoverlapping [1]:
+ // - `src.as_ptr()` is trivially valid for reads of `src.len()` bytes
+ // - `dst.as_ptr()` is valid for writes of `src.len()` bytes, because the
+ // caller has promised that `src.len() <= dst.len()`
+ // - `src` and `dst` are, trivially, properly aligned
+ // - the region of memory beginning at `src` with a size of `src.len()`
+ // bytes does not overlap with the region of memory beginning at `dst`
+ // with the same size, because `dst` is derived from an exclusive
+ // reference.
+ unsafe {
+ core::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), src.len());
+ };
+}
+
+/// Unsafely transmutes the given `src` into a type `Dst`.
+///
+/// # Safety
+///
+/// The value `src` must be a valid instance of `Dst`.
+#[inline(always)]
+pub(crate) const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst {
+ static_assert!(Src, Dst => core::mem::size_of::<Src>() == core::mem::size_of::<Dst>());
+
+ #[repr(C)]
+ union Transmute<Src, Dst> {
+ src: ManuallyDrop<Src>,
+ dst: ManuallyDrop<Dst>,
+ }
+
+ // SAFETY: Since `Transmute<Src, Dst>` is `#[repr(C)]`, its `src` and `dst`
+ // fields both start at the same offset and the types of those fields are
+ // transparent wrappers around `Src` and `Dst` [1]. Consequently,
+ // initializing `Transmute` with with `src` and then reading out `dst` is
+ // equivalent to transmuting from `Src` to `Dst` [2]. Transmuting from `src`
+ // to `Dst` is valid because — by contract on the caller — `src` is a valid
+ // instance of `Dst`.
+ //
+ // [1] Per https://doc.rust-lang.org/1.82.0/std/mem/struct.ManuallyDrop.html:
+ //
+ // `ManuallyDrop<T>` is guaranteed to have the same layout and bit
+ // validity as `T`, and is subject to the same layout optimizations as
+ // `T`.
+ //
+ // [2] Per https://doc.rust-lang.org/1.82.0/reference/items/unions.html#reading-and-writing-union-fields:
+ //
+ // Effectively, writing to and then reading from a union with the C
+ // representation is analogous to a transmute from the type used for
+ // writing to the type used for reading.
+ unsafe { ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst) }
+}
+
+/// # Safety
+///
+/// `Src` must have a greater or equal alignment to `Dst`.
+pub(crate) unsafe fn transmute_ref<Src, Dst, R>(src: &Src) -> &Dst
+where
+ Src: ?Sized,
+ Dst: SizeEq<Src>
+ + TransmuteFromPtr<Src, Shared, Valid, Valid, <Dst as SizeEq<Src>>::CastFrom, R>
+ + ?Sized,
+{
+ let dst = Ptr::from_ref(src).transmute();
+ // SAFETY: The caller promises that `Src`'s alignment is at least as large
+ // as `Dst`'s alignment.
+ let dst = unsafe { dst.assume_alignment() };
+ dst.as_ref()
+}
+
+/// # Safety
+///
+/// `Src` must have a greater or equal alignment to `Dst`.
+pub(crate) unsafe fn transmute_mut<Src, Dst, R>(src: &mut Src) -> &mut Dst
+where
+ Src: ?Sized,
+ Dst: SizeEq<Src>
+ + TransmuteFromPtr<Src, Exclusive, Valid, Valid, <Dst as SizeEq<Src>>::CastFrom, R>
+ + ?Sized,
+{
+ let dst = Ptr::from_mut(src).transmute();
+ // SAFETY: The caller promises that `Src`'s alignment is at least as large
+ // as `Dst`'s alignment.
+ let dst = unsafe { dst.assume_alignment() };
+ dst.as_mut()
+}
+
+/// Uses `allocate` to create a `Box<T>`.
+///
+/// # Errors
+///
+/// Returns an error on allocation failure. Allocation failure is guaranteed
+/// never to cause a panic or an abort.
+///
+/// # Safety
+///
+/// `allocate` must be either `alloc::alloc::alloc` or
+/// `alloc::alloc::alloc_zeroed`. The referent of the box returned by `new_box`
+/// has the same bit-validity as the referent of the pointer returned by the
+/// given `allocate` and sufficient size to store `T` with `meta`.
+#[must_use = "has no side effects (other than allocation)"]
+#[cfg(feature = "alloc")]
+#[inline]
+pub(crate) unsafe fn new_box<T>(
+ meta: T::PointerMetadata,
+ allocate: unsafe fn(core::alloc::Layout) -> *mut u8,
+) -> Result<alloc::boxed::Box<T>, AllocError>
+where
+ T: ?Sized + crate::KnownLayout,
+{
+ let align = T::LAYOUT.align.get();
+ if !T::is_valid_metadata(meta) {
+ return Err(AllocError);
+ }
+ let size = match T::size_for_metadata(meta) {
+ Some(size) => size,
+ // Thanks to the `!T::is_valid_metadata(meta)` check
+ // above, this branch is unreachable. Fortunately, the
+ // optimizer recognizes this, so replacing this branch
+ // with `unreachable_unchecked` produces no codegen
+ // improvements.
+ None => return Err(AllocError),
+ };
+ let ptr = if size != 0 {
+ // SAFETY:
+ // - `align` is derived from a `NonZeroUsize` and is thus non-zero.
+ // - `align` is a power of two because, by invariant on
+ // `KnownLayout::LAYOUT` `<T as KnownLayout>::LAYOUT` accurately
+ // reflects the layout of `T`.
+ // - `size`, by invariant on `size_for_metadata` is well-aligned for
+ // `align` and, by the check on `T::is_valid_metadata(meta)`, is less
+ // than `isize::MAX`.
+ let layout: Layout = unsafe { Layout::from_size_align_unchecked(size, align) };
+ // SAFETY: By contract on the caller, `allocate` is either
+ // `alloc::alloc::alloc` or `alloc::alloc::alloc_zeroed`. The above
+ // check ensures their shared safety precondition: that the supplied
+ // layout is not zero-sized type [1].
+ //
+ // [1] Per https://doc.rust-lang.org/1.81.0/std/alloc/trait.GlobalAlloc.html#tymethod.alloc:
+ //
+ // This function is unsafe because undefined behavior can result if
+ // the caller does not ensure that layout has non-zero size.
+ let ptr = unsafe { allocate(layout) };
+ match NonNull::new(ptr) {
+ Some(ptr) => ptr,
+ None => return Err(AllocError),
+ }
+ } else {
+ // We use `transmute` instead of an `as` cast since Miri (with strict
+ // provenance enabled) notices and complains that an `as` cast creates a
+ // pointer with no provenance. Miri isn't smart enough to realize that
+ // we're only executing this branch when we're constructing a zero-sized
+ // `Box`, which doesn't require provenance.
+ //
+ // SAFETY: any initialized bit sequence is a bit-valid `*mut u8`. All
+ // bits of a `usize` are initialized.
+ //
+ // `#[allow(unknown_lints)]` is for `integer_to_ptr_transmutes`
+ #[allow(unknown_lints)]
+ #[allow(clippy::useless_transmute, integer_to_ptr_transmutes)]
+ let dangling = unsafe { mem::transmute::<usize, *mut u8>(align) };
+ // SAFETY: `dangling` is constructed from `align`, which is derived from
+ // a `NonZeroUsize`, which is guaranteed to be non-zero.
+ //
+ // `Box<[T]>` does not allocate when `T` is zero-sized or when `len` is
+ // zero, but it does require a non-null dangling pointer for its
+ // allocation.
+ //
+ // FIXME(https://github.com/rust-lang/rust/issues/95228): Use
+ // `std::ptr::without_provenance` once it's stable. That may optimize
+ // better. As written, Rust may assume that this consumes "exposed"
+ // provenance, and thus Rust may have to assume that this may consume
+ // provenance from any pointer whose provenance has been exposed.
+ unsafe { NonNull::new_unchecked(dangling) }
+ };
+
+ let ptr = T::raw_from_ptr_len(ptr, meta);
+
+ // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. Make sure to
+ // include a justification that `ptr.as_ptr()` is validly-aligned in the ZST
+ // case (in which we manually construct a dangling pointer) and to justify
+ // why `Box` is safe to drop (it's because `allocate` uses the system
+ // allocator).
+ #[allow(clippy::undocumented_unsafe_blocks)]
+ Ok(unsafe { alloc::boxed::Box::from_raw(ptr.as_ptr()) })
+}
+
+mod len_of {
+ use super::*;
+
+ /// A witness type for metadata of a valid instance of `&T`.
+ pub struct MetadataOf<T: ?Sized + KnownLayout> {
+ /// # Safety
+ ///
+ /// The size of an instance of `&T` with the given metadata is not
+ /// larger than `isize::MAX`.
+ meta: T::PointerMetadata,
+ _p: PhantomData<T>,
+ }
+
+ impl<T: ?Sized + KnownLayout> Copy for MetadataOf<T> {}
+ impl<T: ?Sized + KnownLayout> Clone for MetadataOf<T> {
+ #[inline]
+ fn clone(&self) -> Self {
+ *self
+ }
+ }
+
+ impl<T: ?Sized + KnownLayout> core::fmt::Debug for MetadataOf<T>
+ where
+ T::PointerMetadata: core::fmt::Debug,
+ {
+ #[inline]
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.debug_struct("MetadataOf").field("meta", &self.meta).finish()
+ }
+ }
+
+ impl<T: ?Sized> MetadataOf<T>
+ where
+ T: KnownLayout,
+ {
+ /// Returns `None` if `meta` is greater than `t`'s metadata.
+ #[inline(always)]
+ pub(crate) fn new_in_bounds(t: &T, meta: usize) -> Option<Self>
+ where
+ T: KnownLayout<PointerMetadata = usize>,
+ {
+ if meta <= Ptr::from_ref(t).len() {
+ // SAFETY: We have checked that `meta` is not greater than `t`'s
+ // metadata, which, by invariant on `&T`, addresses no more than
+ // `isize::MAX` bytes [1][2].
+ //
+ // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety:
+ //
+ // For all types, `T: ?Sized`, and for all `t: &T` or `t:
+ // &mut T`, when such values cross an API boundary, the
+ // following invariants must generally be upheld:
+ //
+ // * `t` is non-null
+ // * `t` is aligned to `align_of_val(t)`
+ // * if `size_of_val(t) > 0`, then `t` is dereferenceable for
+ // `size_of_val(t)` many bytes
+ //
+ // If `t` points at address `a`, being "dereferenceable" for
+ // N bytes means that the memory range `[a, a + N)` is all
+ // contained within a single allocated object.
+ //
+ // [2] Per https://doc.rust-lang.org/1.85.0/std/ptr/index.html#allocated-object:
+ //
+ // For any allocated object with `base` address, `size`, and
+ // a set of `addresses`, the following are guaranteed:
+ // - For all addresses `a` in `addresses`, `a` is in the
+ // range `base .. (base + size)` (note that this requires
+ // `a < base + size`, not `a <= base + size`)
+ // - `base` is not equal to [`null()`] (i.e., the address
+ // with the numerical value 0)
+ // - `base + size <= usize::MAX`
+ // - `size <= isize::MAX`
+ Some(unsafe { Self::new_unchecked(meta) })
+ } else {
+ None
+ }
+ }
+
+ /// # Safety
+ ///
+ /// The size of an instance of `&T` with the given metadata is not
+ /// larger than `isize::MAX`.
+ pub(crate) unsafe fn new_unchecked(meta: T::PointerMetadata) -> Self {
+ // SAFETY: The caller has promised that the size of an instance of
+ // `&T` with the given metadata is not larger than `isize::MAX`.
+ Self { meta, _p: PhantomData }
+ }
+
+ pub(crate) fn get(&self) -> T::PointerMetadata
+ where
+ T::PointerMetadata: Copy,
+ {
+ self.meta
+ }
+
+ #[inline]
+ pub(crate) fn padding_needed_for(&self) -> usize
+ where
+ T: KnownLayout<PointerMetadata = usize>,
+ {
+ let trailing_slice_layout = crate::trailing_slice_layout::<T>();
+
+ // FIXME(#67): Remove this allow. See NumExt for more details.
+ #[allow(
+ unstable_name_collisions,
+ clippy::incompatible_msrv,
+ clippy::multiple_unsafe_ops_per_block
+ )]
+ // SAFETY: By invariant on `self`, a `&T` with metadata `self.meta`
+ // describes an object of size `<= isize::MAX`. This computes the
+ // size of such a `&T` without any trailing padding, and so neither
+ // the multiplication nor the addition will overflow.
+ let unpadded_size = unsafe {
+ let trailing_size = self.meta.unchecked_mul(trailing_slice_layout.elem_size);
+ trailing_size.unchecked_add(trailing_slice_layout.offset)
+ };
+
+ util::padding_needed_for(unpadded_size, T::LAYOUT.align)
+ }
+
+ #[inline(always)]
+ pub(crate) fn validate_cast_and_convert_metadata(
+ addr: usize,
+ bytes_len: MetadataOf<[u8]>,
+ cast_type: CastType,
+ meta: Option<T::PointerMetadata>,
+ ) -> Result<(MetadataOf<T>, MetadataOf<[u8]>), MetadataCastError> {
+ let layout = match meta {
+ None => T::LAYOUT,
+ // This can return `Err(MetadataCastError::Size)` if the
+ // metadata describes an object which can't fit in an `isize`.
+ Some(meta) => {
+ if !T::is_valid_metadata(meta) {
+ return Err(MetadataCastError::Size);
+ }
+ let size = match T::size_for_metadata(meta) {
+ Some(size) => size,
+ // Thanks to the `!T::is_valid_metadata(meta)` check
+ // above, this branch is unreachable. Fortunately, the
+ // optimizer recognizes this, so replacing this branch
+ // with `unreachable_unchecked` produces no codegen
+ // improvements.
+ None => return Err(MetadataCastError::Size),
+ };
+ DstLayout {
+ align: T::LAYOUT.align,
+ size_info: crate::SizeInfo::Sized { size },
+ statically_shallow_unpadded: false,
+ }
+ }
+ };
+ // Lemma 0: By contract on `validate_cast_and_convert_metadata`, if
+ // the result is `Ok(..)`, then a `&T` with `elems` trailing slice
+ // elements is no larger in size than `bytes_len.get()`.
+ let (elems, split_at) =
+ layout.validate_cast_and_convert_metadata(addr, bytes_len.get(), cast_type)?;
+ let elems = T::PointerMetadata::from_elem_count(elems);
+
+ // For a slice DST type, if `meta` is `Some(elems)`, then we
+ // synthesize `layout` to describe a sized type whose size is equal
+ // to the size of the instance that we are asked to cast. For sized
+ // types, `validate_cast_and_convert_metadata` returns `elems == 0`.
+ // Thus, in this case, we need to use the `elems` passed by the
+ // caller, not the one returned by
+ // `validate_cast_and_convert_metadata`.
+ //
+ // Lemma 1: A `&T` with `elems` trailing slice elements is no larger
+ // in size than `bytes_len.get()`. Proof:
+ // - If `meta` is `None`, then `elems` satisfies this condition by
+ // Lemma 0.
+ // - If `meta` is `Some(meta)`, then `layout` describes an object
+ // whose size is equal to the size of an `&T` with `meta`
+ // metadata. By Lemma 0, that size is not larger than
+ // `bytes_len.get()`.
+ //
+ // Lemma 2: A `&T` with `elems` trailing slice elements is no larger
+ // than `isize::MAX` bytes. Proof: By Lemma 1, a `&T` with metadata
+ // `elems` is not larger in size than `bytes_len.get()`. By
+ // invariant on `MetadataOf<[u8]>`, a `&[u8]` with metadata
+ // `bytes_len` is not larger than `isize::MAX`. Because
+ // `size_of::<u8>()` is `1`, a `&[u8]` with metadata `bytes_len` has
+ // size `bytes_len.get()` bytes. Therefore, a `&T` with metadata
+ // `elems` has size not larger than `isize::MAX`.
+ let elems = meta.unwrap_or(elems);
+
+ // SAFETY: See Lemma 2.
+ let elems = unsafe { MetadataOf::new_unchecked(elems) };
+
+ // SAFETY: Let `size` be the size of a `&T` with metadata `elems`.
+ // By post-condition on `validate_cast_and_convert_metadata`, one of
+ // the following conditions holds:
+ // - `split_at == size`, in which case, by Lemma 2, `split_at <=
+ // isize::MAX`. Since `size_of::<u8>() == 1`, a `[u8]` with
+ // `split_at` elems has size not larger than `isize::MAX`.
+ // - `split_at == bytes_len - size`. Since `bytes_len:
+ // MetadataOf<u8>`, and since `size` is non-negative, `split_at`
+ // addresses no more bytes than `bytes_len` does. Since
+ // `bytes_len: MetadataOf<u8>`, `bytes_len` describes a `[u8]`
+ // which has no more than `isize::MAX` bytes, and thus so does
+ // `split_at`.
+ let split_at = unsafe { MetadataOf::<[u8]>::new_unchecked(split_at) };
+ Ok((elems, split_at))
+ }
+ }
+}
+
+pub use len_of::MetadataOf;
+
+/// Since we support multiple versions of Rust, there are often features which
+/// have been stabilized in the most recent stable release which do not yet
+/// exist (stably) on our MSRV. This module provides polyfills for those
+/// features so that we can write more "modern" code, and just remove the
+/// polyfill once our MSRV supports the corresponding feature. Without this,
+/// we'd have to write worse/more verbose code and leave FIXME comments
+/// sprinkled throughout the codebase to update to the new pattern once it's
+/// stabilized.
+///
+/// Each trait is imported as `_` at the crate root; each polyfill should "just
+/// work" at usage sites.
+pub(crate) mod polyfills {
+ use core::ptr::{self, NonNull};
+
+ // A polyfill for `NonNull::slice_from_raw_parts` that we can use before our
+ // MSRV is 1.70, when that function was stabilized.
+ //
+ // The `#[allow(unused)]` is necessary because, on sufficiently recent
+ // toolchain versions, `ptr.slice_from_raw_parts()` resolves to the inherent
+ // method rather than to this trait, and so this trait is considered unused.
+ //
+ // FIXME(#67): Once our MSRV is 1.70, remove this.
+ #[allow(unused)]
+ pub(crate) trait NonNullExt<T> {
+ fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]>;
+ }
+
+ impl<T> NonNullExt<T> for NonNull<T> {
+ // NOTE on coverage: this will never be tested in nightly since it's a
+ // polyfill for a feature which has been stabilized on our nightly
+ // toolchain.
+ #[cfg_attr(
+ all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
+ coverage(off)
+ )]
+ #[inline(always)]
+ fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]> {
+ let ptr = ptr::slice_from_raw_parts_mut(data.as_ptr(), len);
+ // SAFETY: `ptr` is converted from `data`, which is non-null.
+ unsafe { NonNull::new_unchecked(ptr) }
+ }
+ }
+
+ // A polyfill for `Self::unchecked_sub` that we can use until methods like
+ // `usize::unchecked_sub` is stabilized.
+ //
+ // The `#[allow(unused)]` is necessary because, on sufficiently recent
+ // toolchain versions, `ptr.slice_from_raw_parts()` resolves to the inherent
+ // method rather than to this trait, and so this trait is considered unused.
+ //
+ // FIXME(#67): Once our MSRV is high enough, remove this.
+ #[allow(unused)]
+ pub(crate) trait NumExt {
+ /// Add without checking for overflow.
+ ///
+ /// # Safety
+ ///
+ /// The caller promises that the addition will not overflow.
+ unsafe fn unchecked_add(self, rhs: Self) -> Self;
+
+ /// Subtract without checking for underflow.
+ ///
+ /// # Safety
+ ///
+ /// The caller promises that the subtraction will not underflow.
+ unsafe fn unchecked_sub(self, rhs: Self) -> Self;
+
+ /// Multiply without checking for overflow.
+ ///
+ /// # Safety
+ ///
+ /// The caller promises that the multiplication will not overflow.
+ unsafe fn unchecked_mul(self, rhs: Self) -> Self;
+ }
+
+ // NOTE on coverage: these will never be tested in nightly since they're
+ // polyfills for a feature which has been stabilized on our nightly
+ // toolchain.
+ impl NumExt for usize {
+ #[cfg_attr(
+ all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
+ coverage(off)
+ )]
+ #[inline(always)]
+ unsafe fn unchecked_add(self, rhs: usize) -> usize {
+ match self.checked_add(rhs) {
+ Some(x) => x,
+ None => {
+ // SAFETY: The caller promises that the addition will not
+ // underflow.
+ unsafe { core::hint::unreachable_unchecked() }
+ }
+ }
+ }
+
+ #[cfg_attr(
+ all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
+ coverage(off)
+ )]
+ #[inline(always)]
+ unsafe fn unchecked_sub(self, rhs: usize) -> usize {
+ match self.checked_sub(rhs) {
+ Some(x) => x,
+ None => {
+ // SAFETY: The caller promises that the subtraction will not
+ // underflow.
+ unsafe { core::hint::unreachable_unchecked() }
+ }
+ }
+ }
+
+ #[cfg_attr(
+ all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
+ coverage(off)
+ )]
+ #[inline(always)]
+ unsafe fn unchecked_mul(self, rhs: usize) -> usize {
+ match self.checked_mul(rhs) {
+ Some(x) => x,
+ None => {
+ // SAFETY: The caller promises that the multiplication will
+ // not overflow.
+ unsafe { core::hint::unreachable_unchecked() }
+ }
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+pub(crate) mod testutil {
+ use crate::*;
+
+ /// A `T` which is aligned to at least `align_of::<A>()`.
+ #[derive(Default)]
+ pub(crate) struct Align<T, A> {
+ pub(crate) t: T,
+ _a: [A; 0],
+ }
+
+ impl<T: Default, A> Align<T, A> {
+ pub(crate) fn set_default(&mut self) {
+ self.t = T::default();
+ }
+ }
+
+ impl<T, A> Align<T, A> {
+ pub(crate) const fn new(t: T) -> Align<T, A> {
+ Align { t, _a: [] }
+ }
+ }
+
+ /// A `T` which is guaranteed not to satisfy `align_of::<A>()`.
+ ///
+ /// It must be the case that `align_of::<T>() < align_of::<A>()` in order
+ /// for this type to work properly.
+ #[repr(C)]
+ pub(crate) struct ForceUnalign<T: Unaligned, A> {
+ // The outer struct is aligned to `A`, and, thanks to `repr(C)`, `t` is
+ // placed at the minimum offset that guarantees its alignment. If
+ // `align_of::<T>() < align_of::<A>()`, then that offset will be
+ // guaranteed *not* to satisfy `align_of::<A>()`.
+ //
+ // Note that we need `T: Unaligned` in order to guarantee that there is
+ // no padding between `_u` and `t`.
+ _u: u8,
+ pub(crate) t: T,
+ _a: [A; 0],
+ }
+
+ impl<T: Unaligned, A> ForceUnalign<T, A> {
+ pub(crate) fn new(t: T) -> ForceUnalign<T, A> {
+ ForceUnalign { _u: 0, t, _a: [] }
+ }
+ }
+ // A `u64` with alignment 8.
+ //
+ // Though `u64` has alignment 8 on some platforms, it's not guaranteed. By
+ // contrast, `AU64` is guaranteed to have alignment 8 on all platforms.
+ #[derive(
+ KnownLayout,
+ Immutable,
+ FromBytes,
+ IntoBytes,
+ Eq,
+ PartialEq,
+ Ord,
+ PartialOrd,
+ Default,
+ Debug,
+ Copy,
+ Clone,
+ )]
+ #[repr(C, align(8))]
+ pub(crate) struct AU64(pub(crate) u64);
+
+ impl AU64 {
+ // Converts this `AU64` to bytes using this platform's endianness.
+ pub(crate) fn to_bytes(self) -> [u8; 8] {
+ crate::transmute!(self)
+ }
+ }
+
+ impl Display for AU64 {
+ #[cfg_attr(
+ all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
+ coverage(off)
+ )]
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ Display::fmt(&self.0, f)
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_round_down_to_next_multiple_of_alignment() {
+ fn alt_impl(n: usize, align: NonZeroUsize) -> usize {
+ let mul = n / align.get();
+ mul * align.get()
+ }
+
+ for align in [1, 2, 4, 8, 16] {
+ for n in 0..256 {
+ let align = NonZeroUsize::new(align).unwrap();
+ let want = alt_impl(n, align);
+ let got = round_down_to_next_multiple_of_alignment(n, align);
+ assert_eq!(got, want, "round_down_to_next_multiple_of_alignment({}, {})", n, align);
+ }
+ }
+ }
+
+ #[rustversion::since(1.57.0)]
+ #[test]
+ #[should_panic]
+ fn test_round_down_to_next_multiple_of_alignment_zerocopy_panic_in_const_and_vec_try_reserve() {
+ round_down_to_next_multiple_of_alignment(0, NonZeroUsize::new(3).unwrap());
+ }
+ #[test]
+ fn test_send_sync_phantom_data() {
+ let x = SendSyncPhantomData::<u8>::default();
+ let y = x.clone();
+ assert!(x == y);
+ assert!(x == SendSyncPhantomData::<u8>::default());
+ }
+
+ #[test]
+ #[allow(clippy::as_conversions)]
+ fn test_as_address() {
+ let x = 0u8;
+ let r = &x;
+ let mut x_mut = 0u8;
+ let rm = &mut x_mut;
+ let p = r as *const u8;
+ let pm = rm as *mut u8;
+ let nn = NonNull::new(p as *mut u8).unwrap();
+
+ assert_eq!(AsAddress::addr(r), p as usize);
+ assert_eq!(AsAddress::addr(rm), pm as usize);
+ assert_eq!(AsAddress::addr(p), p as usize);
+ assert_eq!(AsAddress::addr(pm), pm as usize);
+ assert_eq!(AsAddress::addr(nn), p as usize);
+ }
+}