From 8dd16259287f58f9273002717ec4d27e97127719 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 07:43:14 +0200 Subject: Merging upstream version 127.0. Signed-off-by: Daniel Baumann --- third_party/rust/zerocopy/src/lib.rs | 8256 ++++++++++++++++++++++++++++++++++ 1 file changed, 8256 insertions(+) create mode 100644 third_party/rust/zerocopy/src/lib.rs (limited to 'third_party/rust/zerocopy/src/lib.rs') diff --git a/third_party/rust/zerocopy/src/lib.rs b/third_party/rust/zerocopy/src/lib.rs new file mode 100644 index 0000000000..1e826439ff --- /dev/null +++ b/third_party/rust/zerocopy/src/lib.rs @@ -0,0 +1,8256 @@ +// Copyright 2018 The Fuchsia Authors +// +// Licensed under the 2-Clause BSD License , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +// After updating the following doc comment, make sure to run the following +// command to update `README.md` based on its contents: +// +// ./generate-readme.sh > README.md + +//! *Want to help improve zerocopy? +//! Fill out our [user survey][user-survey]!* +//! +//! ***Fast, safe, compile error. Pick two.*** +//! +//! Zerocopy makes zero-cost memory manipulation effortless. We write `unsafe` +//! so you don't have to. +//! +//! # Overview +//! +//! Zerocopy provides four core marker traits, each of which can be derived +//! (e.g., `#[derive(FromZeroes)]`): +//! - [`FromZeroes`] indicates that a sequence of zero bytes represents a valid +//! instance of a type +//! - [`FromBytes`] indicates that a type may safely be converted from an +//! arbitrary byte sequence +//! - [`AsBytes`] indicates that a type may safely be converted *to* a byte +//! sequence +//! - [`Unaligned`] indicates that a type's alignment requirement is 1 +//! +//! Types which implement a subset of these traits can then be converted to/from +//! byte sequences with little to no runtime overhead. +//! +//! Zerocopy also provides byte-order aware integer types that support these +//! conversions; see the [`byteorder`] module. These types are especially useful +//! for network parsing. +//! +//! [user-survey]: https://docs.google.com/forms/d/e/1FAIpQLSdzBNTN9tzwsmtyZxRFNL02K36IWCdHWW2ZBckyQS2xiO3i8Q/viewform?usp=published_options +//! +//! # Cargo Features +//! +//! - **`alloc`** +//! By default, `zerocopy` is `no_std`. When the `alloc` feature is enabled, +//! the `alloc` crate is added as a dependency, and some allocation-related +//! functionality is added. +//! +//! - **`byteorder`** (enabled by default) +//! Adds the [`byteorder`] module and a dependency on the `byteorder` crate. +//! The `byteorder` module provides byte order-aware equivalents of the +//! multi-byte primitive numerical types. Unlike their primitive equivalents, +//! the types in this module have no alignment requirement and support byte +//! order conversions. This can be useful in handling file formats, network +//! packet layouts, etc which don't provide alignment guarantees and which may +//! use a byte order different from that of the execution platform. +//! +//! - **`derive`** +//! Provides derives for the core marker traits via the `zerocopy-derive` +//! crate. These derives are re-exported from `zerocopy`, so it is not +//! necessary to depend on `zerocopy-derive` directly. +//! +//! However, you may experience better compile times if you instead directly +//! depend on both `zerocopy` and `zerocopy-derive` in your `Cargo.toml`, +//! since doing so will allow Rust to compile these crates in parallel. To do +//! so, do *not* enable the `derive` feature, and list both dependencies in +//! your `Cargo.toml` with the same leading non-zero version number; e.g: +//! +//! ```toml +//! [dependencies] +//! zerocopy = "0.X" +//! zerocopy-derive = "0.X" +//! ``` +//! +//! - **`simd`** +//! When the `simd` feature is enabled, `FromZeroes`, `FromBytes`, and +//! `AsBytes` impls are emitted for all stable SIMD types which exist on the +//! target platform. Note that the layout of SIMD types is not yet stabilized, +//! so these impls may be removed in the future if layout changes make them +//! invalid. For more information, see the Unsafe Code Guidelines Reference +//! page on the [layout of packed SIMD vectors][simd-layout]. +//! +//! - **`simd-nightly`** +//! Enables the `simd` feature and adds support for SIMD types which are only +//! available on nightly. Since these types are unstable, support for any type +//! may be removed at any point in the future. +//! +//! [simd-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html +//! +//! # Security Ethos +//! +//! Zerocopy is expressly designed for use in security-critical contexts. We +//! strive to ensure that that zerocopy code is sound under Rust's current +//! memory model, and *any future memory model*. We ensure this by: +//! - **...not 'guessing' about Rust's semantics.** +//! We annotate `unsafe` code with a precise rationale for its soundness that +//! cites a relevant section of Rust's official documentation. When Rust's +//! documented semantics are unclear, we work with the Rust Operational +//! Semantics Team to clarify Rust's documentation. +//! - **...rigorously testing our implementation.** +//! We run tests using [Miri], ensuring that zerocopy is sound across a wide +//! array of supported target platforms of varying endianness and pointer +//! width, and across both current and experimental memory models of Rust. +//! - **...formally proving the correctness of our implementation.** +//! We apply formal verification tools like [Kani][kani] to prove zerocopy's +//! correctness. +//! +//! For more information, see our full [soundness policy]. +//! +//! [Miri]: https://github.com/rust-lang/miri +//! [Kani]: https://github.com/model-checking/kani +//! [soundness policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#soundness +//! +//! # Relationship to Project Safe Transmute +//! +//! [Project Safe Transmute] is an official initiative of the Rust Project to +//! develop language-level support for safer transmutation. The Project consults +//! with crates like zerocopy to identify aspects of safer transmutation that +//! would benefit from compiler support, and has developed an [experimental, +//! compiler-supported analysis][mcp-transmutability] which determines whether, +//! for a given type, any value of that type may be soundly transmuted into +//! another type. Once this functionality is sufficiently mature, zerocopy +//! intends to replace its internal transmutability analysis (implemented by our +//! custom derives) with the compiler-supported one. This change will likely be +//! an implementation detail that is invisible to zerocopy's users. +//! +//! Project Safe Transmute will not replace the need for most of zerocopy's +//! higher-level abstractions. The experimental compiler analysis is a tool for +//! checking the soundness of `unsafe` code, not a tool to avoid writing +//! `unsafe` code altogether. For the foreseeable future, crates like zerocopy +//! will still be required in order to provide higher-level abstractions on top +//! of the building block provided by Project Safe Transmute. +//! +//! [Project Safe Transmute]: https://rust-lang.github.io/rfcs/2835-project-safe-transmute.html +//! [mcp-transmutability]: https://github.com/rust-lang/compiler-team/issues/411 +//! +//! # MSRV +//! +//! See our [MSRV policy]. +//! +//! [MSRV policy]: https://github.com/google/zerocopy/blob/main/POLICIES.md#msrv +//! +//! # Changelog +//! +//! Zerocopy uses [GitHub Releases]. +//! +//! [GitHub Releases]: https://github.com/google/zerocopy/releases + +// Sometimes we want to use lints which were added after our MSRV. +// `unknown_lints` is `warn` by default and we deny warnings in CI, so without +// this attribute, any unknown lint would cause a CI failure when testing with +// our MSRV. +#![allow(unknown_lints)] +#![deny(renamed_and_removed_lints)] +#![deny( + anonymous_parameters, + deprecated_in_future, + illegal_floating_point_literal_pattern, + late_bound_lifetime_arguments, + missing_copy_implementations, + missing_debug_implementations, + missing_docs, + path_statements, + patterns_in_fns_without_body, + rust_2018_idioms, + trivial_numeric_casts, + unreachable_pub, + unsafe_op_in_unsafe_fn, + unused_extern_crates, + unused_qualifications, + variant_size_differences +)] +#![cfg_attr( + __INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS, + deny(fuzzy_provenance_casts, lossy_provenance_casts) +)] +#![deny( + clippy::all, + clippy::alloc_instead_of_core, + clippy::arithmetic_side_effects, + clippy::as_underscore, + clippy::assertions_on_result_states, + clippy::as_conversions, + clippy::correctness, + clippy::dbg_macro, + clippy::decimal_literal_representation, + clippy::get_unwrap, + clippy::indexing_slicing, + clippy::missing_inline_in_public_items, + clippy::missing_safety_doc, + clippy::obfuscated_if_else, + clippy::perf, + clippy::print_stdout, + clippy::std_instead_of_core, + clippy::style, + clippy::suspicious, + clippy::todo, + clippy::undocumented_unsafe_blocks, + clippy::unimplemented, + clippy::unnested_or_patterns, + clippy::unwrap_used, + clippy::use_debug +)] +#![deny( + rustdoc::bare_urls, + rustdoc::broken_intra_doc_links, + rustdoc::invalid_codeblock_attributes, + rustdoc::invalid_html_tags, + rustdoc::invalid_rust_codeblocks, + rustdoc::missing_crate_level_docs, + rustdoc::private_intra_doc_links +)] +// In test code, it makes sense to weight more heavily towards concise, readable +// code over correct or debuggable code. +#![cfg_attr(any(test, kani), allow( + // In tests, you get line numbers and have access to source code, so panic + // messages are less important. You also often unwrap a lot, which would + // make expect'ing instead very verbose. + clippy::unwrap_used, + // In tests, there's no harm to "panic risks" - the worst that can happen is + // that your test will fail, and you'll fix it. By contrast, panic risks in + // production code introduce the possibly of code panicking unexpectedly "in + // the field". + clippy::arithmetic_side_effects, + clippy::indexing_slicing, +))] +#![cfg_attr(not(test), no_std)] +#![cfg_attr(feature = "simd-nightly", feature(stdsimd))] +#![cfg_attr(doc_cfg, feature(doc_cfg))] +#![cfg_attr( + __INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS, + feature(layout_for_ptr, strict_provenance) +)] + +// This is a hack to allow zerocopy-derive derives to work in this crate. They +// assume that zerocopy is linked as an extern crate, so they access items from +// it as `zerocopy::Xxx`. This makes that still work. +#[cfg(any(feature = "derive", test))] +extern crate self as zerocopy; + +#[macro_use] +mod macros; + +#[cfg(feature = "byteorder")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "byteorder")))] +pub mod byteorder; +#[doc(hidden)] +pub mod macro_util; +mod post_monomorphization_compile_fail_tests; +mod util; +// TODO(#252): If we make this pub, come up with a better name. +mod wrappers; + +#[cfg(feature = "byteorder")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "byteorder")))] +pub use crate::byteorder::*; +pub use crate::wrappers::*; + +#[cfg(any(feature = "derive", test))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub use zerocopy_derive::Unaligned; + +// `pub use` separately here so that we can mark it `#[doc(hidden)]`. +// +// TODO(#29): Remove this or add a doc comment. +#[cfg(any(feature = "derive", test))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +#[doc(hidden)] +pub use zerocopy_derive::KnownLayout; + +use core::{ + cell::{self, RefMut}, + cmp::Ordering, + fmt::{self, Debug, Display, Formatter}, + hash::Hasher, + marker::PhantomData, + mem::{self, ManuallyDrop, MaybeUninit}, + num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128, + NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping, + }, + ops::{Deref, DerefMut}, + ptr::{self, NonNull}, + slice, +}; + +#[cfg(feature = "alloc")] +extern crate alloc; +#[cfg(feature = "alloc")] +use alloc::{boxed::Box, vec::Vec}; + +#[cfg(any(feature = "alloc", kani))] +use core::alloc::Layout; + +// Used by `TryFromBytes::is_bit_valid`. +#[doc(hidden)] +pub use crate::util::ptr::Ptr; + +// For each polyfill, as soon as the corresponding feature is stable, the +// polyfill import will be unused because method/function resolution will prefer +// the inherent method/function over a trait method/function. Thus, we suppress +// the `unused_imports` warning. +// +// See the documentation on `util::polyfills` for more information. +#[allow(unused_imports)] +use crate::util::polyfills::NonNullExt as _; + +#[rustversion::nightly] +#[cfg(all(test, not(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)))] +const _: () = { + #[deprecated = "some tests may be skipped due to missing RUSTFLAGS=\"--cfg __INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS\""] + const _WARNING: () = (); + #[warn(deprecated)] + _WARNING +}; + +/// The target pointer width, counted in bits. +const POINTER_WIDTH_BITS: usize = mem::size_of::() * 8; + +/// The layout of a type which might be dynamically-sized. +/// +/// `DstLayout` describes the layout of sized types, slice types, and "slice +/// DSTs" - ie, those that are known by the type system to have a trailing slice +/// (as distinguished from `dyn Trait` types - such types *might* have a +/// trailing slice type, but the type system isn't aware of it). +/// +/// # Safety +/// +/// Unlike [`core::alloc::Layout`], `DstLayout` is only used to describe full +/// Rust types - ie, those that satisfy the layout requirements outlined by +/// [the reference]. Callers may assume that an instance of `DstLayout` +/// satisfies any conditions imposed on Rust types by the reference. +/// +/// If `layout: DstLayout` describes a type, `T`, then it is guaranteed that: +/// - `layout.align` is equal to `T`'s alignment +/// - If `layout.size_info` is `SizeInfo::Sized { size }`, then `T: Sized` and +/// `size_of::() == size` +/// - If `layout.size_info` is `SizeInfo::SliceDst(slice_layout)`, then +/// - `T` is a slice DST +/// - The `size` of an instance of `T` with `elems` trailing slice elements is +/// equal to `slice_layout.offset + slice_layout.elem_size * elems` rounded up +/// to the nearest multiple of `layout.align`. Any bytes in the range +/// `[slice_layout.offset + slice_layout.elem_size * elems, size)` are padding +/// and must not be assumed to be initialized. +/// +/// [the reference]: https://doc.rust-lang.org/reference/type-layout.html +#[doc(hidden)] +#[allow(missing_debug_implementations, missing_copy_implementations)] +#[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))] +pub struct DstLayout { + align: NonZeroUsize, + size_info: SizeInfo, +} + +#[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))] +enum SizeInfo { + Sized { _size: usize }, + SliceDst(TrailingSliceLayout), +} + +#[cfg_attr(any(kani, test), derive(Copy, Clone, Debug, PartialEq, Eq))] +struct TrailingSliceLayout { + // The offset of the first byte of the trailing slice field. Note that this + // is NOT the same as the minimum size of the type. For example, consider + // the following type: + // + // struct Foo { + // a: u16, + // b: u8, + // c: [u8], + // } + // + // In `Foo`, `c` is at byte offset 3. When `c.len() == 0`, `c` is followed + // by a padding byte. + _offset: usize, + // The size of the element type of the trailing slice field. + _elem_size: E, +} + +impl SizeInfo { + /// Attempts to create a `SizeInfo` from `Self` in which `elem_size` is a + /// `NonZeroUsize`. If `elem_size` is 0, returns `None`. + #[allow(unused)] + const fn try_to_nonzero_elem_size(&self) -> Option> { + Some(match *self { + SizeInfo::Sized { _size } => SizeInfo::Sized { _size }, + SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size }) => { + if let Some(_elem_size) = NonZeroUsize::new(_elem_size) { + SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size }) + } else { + return None; + } + } + }) + } +} + +#[doc(hidden)] +#[derive(Copy, Clone)] +#[cfg_attr(test, derive(Debug))] +#[allow(missing_debug_implementations)] +pub enum _CastType { + _Prefix, + _Suffix, +} + +impl DstLayout { + /// The minimum possible alignment of a type. + const MIN_ALIGN: NonZeroUsize = match NonZeroUsize::new(1) { + Some(min_align) => min_align, + None => unreachable!(), + }; + + /// The maximum theoretic possible alignment of a type. + /// + /// For compatibility with future Rust versions, this is defined as the + /// maximum power-of-two that fits into a `usize`. See also + /// [`DstLayout::CURRENT_MAX_ALIGN`]. + const THEORETICAL_MAX_ALIGN: NonZeroUsize = + match NonZeroUsize::new(1 << (POINTER_WIDTH_BITS - 1)) { + Some(max_align) => max_align, + None => unreachable!(), + }; + + /// The current, documented max alignment of a type \[1\]. + /// + /// \[1\] Per : + /// + /// The alignment value must be a power of two from 1 up to + /// 229. + #[cfg(not(kani))] + const CURRENT_MAX_ALIGN: NonZeroUsize = match NonZeroUsize::new(1 << 28) { + Some(max_align) => max_align, + None => unreachable!(), + }; + + /// Constructs a `DstLayout` for a zero-sized type with `repr_align` + /// alignment (or 1). If `repr_align` is provided, then it must be a power + /// of two. + /// + /// # Panics + /// + /// This function panics if the supplied `repr_align` is not a power of two. + /// + /// # Safety + /// + /// Unsafe code may assume that the contract of this function is satisfied. + #[doc(hidden)] + #[inline] + pub const fn new_zst(repr_align: Option) -> DstLayout { + let align = match repr_align { + Some(align) => align, + None => Self::MIN_ALIGN, + }; + + assert!(align.is_power_of_two()); + + DstLayout { align, size_info: SizeInfo::Sized { _size: 0 } } + } + + /// Constructs a `DstLayout` which describes `T`. + /// + /// # Safety + /// + /// Unsafe code may assume that `DstLayout` is the correct layout for `T`. + #[doc(hidden)] + #[inline] + pub const fn for_type() -> DstLayout { + // SAFETY: `align` is correct by construction. `T: Sized`, and so it is + // sound to initialize `size_info` to `SizeInfo::Sized { size }`; the + // `size` field is also correct by construction. + DstLayout { + align: match NonZeroUsize::new(mem::align_of::()) { + Some(align) => align, + None => unreachable!(), + }, + size_info: SizeInfo::Sized { _size: mem::size_of::() }, + } + } + + /// Constructs a `DstLayout` which describes `[T]`. + /// + /// # Safety + /// + /// Unsafe code may assume that `DstLayout` is the correct layout for `[T]`. + const fn for_slice() -> DstLayout { + // SAFETY: The alignment of a slice is equal to the alignment of its + // element type, and so `align` is initialized correctly. + // + // Since this is just a slice type, there is no offset between the + // beginning of the type and the beginning of the slice, so it is + // correct to set `offset: 0`. The `elem_size` is correct by + // construction. Since `[T]` is a (degenerate case of a) slice DST, it + // is correct to initialize `size_info` to `SizeInfo::SliceDst`. + DstLayout { + align: match NonZeroUsize::new(mem::align_of::()) { + Some(align) => align, + None => unreachable!(), + }, + size_info: SizeInfo::SliceDst(TrailingSliceLayout { + _offset: 0, + _elem_size: mem::size_of::(), + }), + } + } + + /// Like `Layout::extend`, this creates a layout that describes a record + /// whose layout consists of `self` followed by `next` that includes the + /// necessary inter-field padding, but not any trailing padding. + /// + /// In order to match the layout of a `#[repr(C)]` struct, this method + /// should be invoked for each field in declaration order. To add trailing + /// padding, call `DstLayout::pad_to_align` after extending the layout for + /// all fields. If `self` corresponds to a type marked with + /// `repr(packed(N))`, then `repr_packed` should be set to `Some(N)`, + /// otherwise `None`. + /// + /// This method cannot be used to match the layout of a record with the + /// default representation, as that representation is mostly unspecified. + /// + /// # Safety + /// + /// If a (potentially hypothetical) valid `repr(C)` Rust type begins with + /// fields whose layout are `self`, and those fields are immediately + /// followed by a field whose layout is `field`, then unsafe code may rely + /// on `self.extend(field, repr_packed)` producing a layout that correctly + /// encompasses those two components. + /// + /// We make no guarantees to the behavior of this method if these fragments + /// cannot appear in a valid Rust type (e.g., the concatenation of the + /// layouts would lead to a size larger than `isize::MAX`). + #[doc(hidden)] + #[inline] + pub const fn extend(self, field: DstLayout, repr_packed: Option) -> Self { + use util::{core_layout::padding_needed_for, max, min}; + + // If `repr_packed` is `None`, there are no alignment constraints, and + // the value can be defaulted to `THEORETICAL_MAX_ALIGN`. + let max_align = match repr_packed { + Some(max_align) => max_align, + None => Self::THEORETICAL_MAX_ALIGN, + }; + + assert!(max_align.is_power_of_two()); + + // We use Kani to prove that this method is robust to future increases + // in Rust's maximum allowed alignment. However, if such a change ever + // actually occurs, we'd like to be notified via assertion failures. + #[cfg(not(kani))] + { + debug_assert!(self.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); + debug_assert!(field.align.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); + if let Some(repr_packed) = repr_packed { + debug_assert!(repr_packed.get() <= DstLayout::CURRENT_MAX_ALIGN.get()); + } + } + + // The field's alignment is clamped by `repr_packed` (i.e., the + // `repr(packed(N))` attribute, if any) [1]. + // + // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers: + // + // The alignments of each field, for the purpose of positioning + // fields, is the smaller of the specified alignment and the alignment + // of the field's type. + let field_align = min(field.align, max_align); + + // The struct's alignment is the maximum of its previous alignment and + // `field_align`. + let align = max(self.align, field_align); + + let size_info = match self.size_info { + // If the layout is already a DST, we panic; DSTs cannot be extended + // with additional fields. + SizeInfo::SliceDst(..) => panic!("Cannot extend a DST with additional fields."), + + SizeInfo::Sized { _size: preceding_size } => { + // Compute the minimum amount of inter-field padding needed to + // satisfy the field's alignment, and offset of the trailing + // field. [1] + // + // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers: + // + // Inter-field padding is guaranteed to be the minimum + // required in order to satisfy each field's (possibly + // altered) alignment. + let padding = padding_needed_for(preceding_size, field_align); + + // This will not panic (and is proven to not panic, with Kani) + // if the layout components can correspond to a leading layout + // fragment of a valid Rust type, but may panic otherwise (e.g., + // combining or aligning the components would create a size + // exceeding `isize::MAX`). + let offset = match preceding_size.checked_add(padding) { + Some(offset) => offset, + None => panic!("Adding padding to `self`'s size overflows `usize`."), + }; + + match field.size_info { + SizeInfo::Sized { _size: field_size } => { + // If the trailing field is sized, the resulting layout + // will be sized. Its size will be the sum of the + // preceeding layout, the size of the new field, and the + // size of inter-field padding between the two. + // + // This will not panic (and is proven with Kani to not + // panic) if the layout components can correspond to a + // leading layout fragment of a valid Rust type, but may + // panic otherwise (e.g., combining or aligning the + // components would create a size exceeding + // `usize::MAX`). + let size = match offset.checked_add(field_size) { + Some(size) => size, + None => panic!("`field` cannot be appended without the total size overflowing `usize`"), + }; + SizeInfo::Sized { _size: size } + } + SizeInfo::SliceDst(TrailingSliceLayout { + _offset: trailing_offset, + _elem_size, + }) => { + // If the trailing field is dynamically sized, so too + // will the resulting layout. The offset of the trailing + // slice component is the sum of the offset of the + // trailing field and the trailing slice offset within + // that field. + // + // This will not panic (and is proven with Kani to not + // panic) if the layout components can correspond to a + // leading layout fragment of a valid Rust type, but may + // panic otherwise (e.g., combining or aligning the + // components would create a size exceeding + // `usize::MAX`). + let offset = match offset.checked_add(trailing_offset) { + Some(offset) => offset, + None => panic!("`field` cannot be appended without the total size overflowing `usize`"), + }; + SizeInfo::SliceDst(TrailingSliceLayout { _offset: offset, _elem_size }) + } + } + } + }; + + DstLayout { align, size_info } + } + + /// Like `Layout::pad_to_align`, this routine rounds the size of this layout + /// up to the nearest multiple of this type's alignment or `repr_packed` + /// (whichever is less). This method leaves DST layouts unchanged, since the + /// trailing padding of DSTs is computed at runtime. + /// + /// In order to match the layout of a `#[repr(C)]` struct, this method + /// should be invoked after the invocations of [`DstLayout::extend`]. If + /// `self` corresponds to a type marked with `repr(packed(N))`, then + /// `repr_packed` should be set to `Some(N)`, otherwise `None`. + /// + /// This method cannot be used to match the layout of a record with the + /// default representation, as that representation is mostly unspecified. + /// + /// # Safety + /// + /// If a (potentially hypothetical) valid `repr(C)` type begins with fields + /// whose layout are `self` followed only by zero or more bytes of trailing + /// padding (not included in `self`), then unsafe code may rely on + /// `self.pad_to_align(repr_packed)` producing a layout that correctly + /// encapsulates the layout of that type. + /// + /// We make no guarantees to the behavior of this method if `self` cannot + /// appear in a valid Rust type (e.g., because the addition of trailing + /// padding would lead to a size larger than `isize::MAX`). + #[doc(hidden)] + #[inline] + pub const fn pad_to_align(self) -> Self { + use util::core_layout::padding_needed_for; + + let size_info = match self.size_info { + // For sized layouts, we add the minimum amount of trailing padding + // needed to satisfy alignment. + SizeInfo::Sized { _size: unpadded_size } => { + let padding = padding_needed_for(unpadded_size, self.align); + let size = match unpadded_size.checked_add(padding) { + Some(size) => size, + None => panic!("Adding padding caused size to overflow `usize`."), + }; + SizeInfo::Sized { _size: size } + } + // For DST layouts, trailing padding depends on the length of the + // trailing DST and is computed at runtime. This does not alter the + // offset or element size of the layout, so we leave `size_info` + // unchanged. + size_info @ SizeInfo::SliceDst(_) => size_info, + }; + + DstLayout { align: self.align, size_info } + } + + /// Validates that a cast is sound from a layout perspective. + /// + /// Validates that the size and alignment requirements of a type with the + /// layout described in `self` would not be violated by performing a + /// `cast_type` cast from a pointer with address `addr` which refers to a + /// memory region of size `bytes_len`. + /// + /// If the cast is valid, `validate_cast_and_convert_metadata` returns + /// `(elems, split_at)`. If `self` describes a dynamically-sized type, then + /// `elems` is the maximum number of trailing slice elements for which a + /// cast would be valid (for sized types, `elem` is meaningless and should + /// be ignored). `split_at` is the index at which to split the memory region + /// in order for the prefix (suffix) to contain the result of the cast, and + /// in order for the remaining suffix (prefix) to contain the leftover + /// bytes. + /// + /// There are three conditions under which a cast can fail: + /// - The smallest possible value for the type is larger than the provided + /// memory region + /// - A prefix cast is requested, and `addr` does not satisfy `self`'s + /// alignment requirement + /// - A suffix cast is requested, and `addr + bytes_len` does not satisfy + /// `self`'s alignment requirement (as a consequence, since all instances + /// of the type are a multiple of its alignment, no size for the type will + /// result in a starting address which is properly aligned) + /// + /// # Safety + /// + /// The caller may assume that this implementation is correct, and may rely + /// on that assumption for the soundness of their code. In particular, the + /// caller may assume that, if `validate_cast_and_convert_metadata` returns + /// `Some((elems, split_at))`, then: + /// - A pointer to the type (for dynamically sized types, this includes + /// `elems` as its pointer metadata) describes an object of size `size <= + /// bytes_len` + /// - If this is a prefix cast: + /// - `addr` satisfies `self`'s alignment + /// - `size == split_at` + /// - If this is a suffix cast: + /// - `split_at == bytes_len - size` + /// - `addr + split_at` satisfies `self`'s alignment + /// + /// Note that this method does *not* ensure that a pointer constructed from + /// its return values will be a valid pointer. In particular, this method + /// does not reason about `isize` overflow, which is a requirement of many + /// Rust pointer APIs, and may at some point be determined to be a validity + /// invariant of pointer types themselves. This should never be a problem so + /// long as the arguments to this method are derived from a known-valid + /// pointer (e.g., one derived from a safe Rust reference), but it is + /// nonetheless the caller's responsibility to justify that pointer + /// arithmetic will not overflow based on a safety argument *other than* the + /// mere fact that this method returned successfully. + /// + /// # Panics + /// + /// `validate_cast_and_convert_metadata` will panic if `self` describes a + /// DST whose trailing slice element is zero-sized. + /// + /// If `addr + bytes_len` overflows `usize`, + /// `validate_cast_and_convert_metadata` may panic, or it may return + /// incorrect results. No guarantees are made about when + /// `validate_cast_and_convert_metadata` will panic. The caller should not + /// rely on `validate_cast_and_convert_metadata` panicking in any particular + /// condition, even if `debug_assertions` are enabled. + #[allow(unused)] + const fn validate_cast_and_convert_metadata( + &self, + addr: usize, + bytes_len: usize, + cast_type: _CastType, + ) -> Option<(usize, usize)> { + // `debug_assert!`, but with `#[allow(clippy::arithmetic_side_effects)]`. + macro_rules! __debug_assert { + ($e:expr $(, $msg:expr)?) => { + debug_assert!({ + #[allow(clippy::arithmetic_side_effects)] + let e = $e; + e + } $(, $msg)?); + }; + } + + // Note that, in practice, `self` is always a compile-time constant. We + // do this check earlier than needed to ensure that we always panic as a + // result of bugs in the program (such as calling this function on an + // invalid type) instead of allowing this panic to be hidden if the cast + // would have failed anyway for runtime reasons (such as a too-small + // memory region). + // + // TODO(#67): Once our MSRV is 1.65, use let-else: + // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements + let size_info = match self.size_info.try_to_nonzero_elem_size() { + Some(size_info) => size_info, + None => panic!("attempted to cast to slice type with zero-sized element"), + }; + + // Precondition + __debug_assert!(addr.checked_add(bytes_len).is_some(), "`addr` + `bytes_len` > usize::MAX"); + + // Alignment checks go in their own block to avoid introducing variables + // into the top-level scope. + { + // We check alignment for `addr` (for prefix casts) or `addr + + // bytes_len` (for suffix casts). For a prefix cast, the correctness + // of this check is trivial - `addr` is the address the object will + // live at. + // + // For a suffix cast, we know that all valid sizes for the type are + // a multiple of the alignment (and by safety precondition, we know + // `DstLayout` may only describe valid Rust types). Thus, a + // validly-sized instance which lives at a validly-aligned address + // must also end at a validly-aligned address. Thus, if the end + // address for a suffix cast (`addr + bytes_len`) is not aligned, + // then no valid start address will be aligned either. + let offset = match cast_type { + _CastType::_Prefix => 0, + _CastType::_Suffix => bytes_len, + }; + + // Addition is guaranteed not to overflow because `offset <= + // bytes_len`, and `addr + bytes_len <= usize::MAX` is a + // precondition of this method. Modulus is guaranteed not to divide + // by 0 because `align` is non-zero. + #[allow(clippy::arithmetic_side_effects)] + if (addr + offset) % self.align.get() != 0 { + return None; + } + } + + let (elems, self_bytes) = match size_info { + SizeInfo::Sized { _size: size } => { + if size > bytes_len { + return None; + } + (0, size) + } + SizeInfo::SliceDst(TrailingSliceLayout { _offset: offset, _elem_size: elem_size }) => { + // Calculate the maximum number of bytes that could be consumed + // - any number of bytes larger than this will either not be a + // multiple of the alignment, or will be larger than + // `bytes_len`. + let max_total_bytes = + util::round_down_to_next_multiple_of_alignment(bytes_len, self.align); + // Calculate the maximum number of bytes that could be consumed + // by the trailing slice. + // + // TODO(#67): Once our MSRV is 1.65, use let-else: + // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#let-else-statements + let max_slice_and_padding_bytes = match max_total_bytes.checked_sub(offset) { + Some(max) => max, + // `bytes_len` too small even for 0 trailing slice elements. + None => return None, + }; + + // Calculate the number of elements that fit in + // `max_slice_and_padding_bytes`; any remaining bytes will be + // considered padding. + // + // Guaranteed not to divide by zero: `elem_size` is non-zero. + #[allow(clippy::arithmetic_side_effects)] + let elems = max_slice_and_padding_bytes / elem_size.get(); + // Guaranteed not to overflow on multiplication: `usize::MAX >= + // max_slice_and_padding_bytes >= (max_slice_and_padding_bytes / + // elem_size) * elem_size`. + // + // Guaranteed not to overflow on addition: + // - max_slice_and_padding_bytes == max_total_bytes - offset + // - elems * elem_size <= max_slice_and_padding_bytes == max_total_bytes - offset + // - elems * elem_size + offset <= max_total_bytes <= usize::MAX + #[allow(clippy::arithmetic_side_effects)] + let without_padding = offset + elems * elem_size.get(); + // `self_bytes` is equal to the offset bytes plus the bytes + // consumed by the trailing slice plus any padding bytes + // required to satisfy the alignment. Note that we have computed + // the maximum number of trailing slice elements that could fit + // in `self_bytes`, so any padding is guaranteed to be less than + // the size of an extra element. + // + // Guaranteed not to overflow: + // - By previous comment: without_padding == elems * elem_size + + // offset <= max_total_bytes + // - By construction, `max_total_bytes` is a multiple of + // `self.align`. + // - At most, adding padding needed to round `without_padding` + // up to the next multiple of the alignment will bring + // `self_bytes` up to `max_total_bytes`. + #[allow(clippy::arithmetic_side_effects)] + let self_bytes = without_padding + + util::core_layout::padding_needed_for(without_padding, self.align); + (elems, self_bytes) + } + }; + + __debug_assert!(self_bytes <= bytes_len); + + let split_at = match cast_type { + _CastType::_Prefix => self_bytes, + // Guaranteed not to underflow: + // - In the `Sized` branch, only returns `size` if `size <= + // bytes_len`. + // - In the `SliceDst` branch, calculates `self_bytes <= + // max_toatl_bytes`, which is upper-bounded by `bytes_len`. + #[allow(clippy::arithmetic_side_effects)] + _CastType::_Suffix => bytes_len - self_bytes, + }; + + Some((elems, split_at)) + } +} + +/// A trait which carries information about a type's layout that is used by the +/// internals of this crate. +/// +/// This trait is not meant for consumption by code outside of this crate. While +/// the normal semver stability guarantees apply with respect to which types +/// implement this trait and which trait implementations are implied by this +/// trait, no semver stability guarantees are made regarding its internals; they +/// may change at any time, and code which makes use of them may break. +/// +/// # Safety +/// +/// This trait does not convey any safety guarantees to code outside this crate. +#[doc(hidden)] // TODO: Remove this once KnownLayout is used by other APIs +pub unsafe trait KnownLayout { + // The `Self: Sized` bound makes it so that `KnownLayout` can still be + // object safe. It's not currently object safe thanks to `const LAYOUT`, and + // it likely won't be in the future, but there's no reason not to be + // forwards-compatible with object safety. + #[doc(hidden)] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized; + + #[doc(hidden)] + const LAYOUT: DstLayout; + + /// SAFETY: The returned pointer has the same address and provenance as + /// `bytes`. If `Self` is a DST, the returned pointer's referent has `elems` + /// elements in its trailing slice. If `Self` is sized, `elems` is ignored. + #[doc(hidden)] + fn raw_from_ptr_len(bytes: NonNull, elems: usize) -> NonNull; +} + +// SAFETY: Delegates safety to `DstLayout::for_slice`. +unsafe impl KnownLayout for [T] { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized, + { + } + const LAYOUT: DstLayout = DstLayout::for_slice::(); + + // SAFETY: `.cast` preserves address and provenance. The returned pointer + // refers to an object with `elems` elements by construction. + #[inline(always)] + fn raw_from_ptr_len(data: NonNull, elems: usize) -> NonNull { + // TODO(#67): Remove this allow. See NonNullExt for more details. + #[allow(unstable_name_collisions)] + NonNull::slice_from_raw_parts(data.cast::(), elems) + } +} + +#[rustfmt::skip] +impl_known_layout!( + (), + u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64, + bool, char, + NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, + NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize +); +#[rustfmt::skip] +impl_known_layout!( + T => Option, + T: ?Sized => PhantomData, + T => Wrapping, + T => MaybeUninit, + T: ?Sized => *const T, + T: ?Sized => *mut T, +); +impl_known_layout!(const N: usize, T => [T; N]); + +safety_comment! { + /// SAFETY: + /// `str` and `ManuallyDrop<[T]>` [1] have the same representations as + /// `[u8]` and `[T]` repsectively. `str` has different bit validity than + /// `[u8]`, but that doesn't affect the soundness of this impl. + /// + /// [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: + /// + /// `ManuallyDrop` is guaranteed to have the same layout and bit + /// validity as `T` + /// + /// TODO(#429): + /// - Add quotes from docs. + /// - Once [1] (added in + /// https://github.com/rust-lang/rust/pull/115522) is available on stable, + /// quote the stable docs instead of the nightly docs. + unsafe_impl_known_layout!(#[repr([u8])] str); + unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] ManuallyDrop); +} + +/// Analyzes whether a type is [`FromZeroes`]. +/// +/// This derive analyzes, at compile time, whether the annotated type satisfies +/// the [safety conditions] of `FromZeroes` and implements `FromZeroes` if it is +/// sound to do so. This derive can be applied to structs, enums, and unions; +/// e.g.: +/// +/// ``` +/// # use zerocopy_derive::FromZeroes; +/// #[derive(FromZeroes)] +/// struct MyStruct { +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes)] +/// #[repr(u8)] +/// enum MyEnum { +/// # Variant0, +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes)] +/// union MyUnion { +/// # variant: u8, +/// # /* +/// ... +/// # */ +/// } +/// ``` +/// +/// [safety conditions]: trait@FromZeroes#safety +/// +/// # Analysis +/// +/// *This section describes, roughly, the analysis performed by this derive to +/// determine whether it is sound to implement `FromZeroes` for a given type. +/// Unless you are modifying the implementation of this derive, or attempting to +/// manually implement `FromZeroes` for a type yourself, you don't need to read +/// this section.* +/// +/// If a type has the following properties, then this derive can implement +/// `FromZeroes` for that type: +/// +/// - If the type is a struct, all of its fields must be `FromZeroes`. +/// - If the type is an enum, it must be C-like (meaning that all variants have +/// no fields) and it must have a variant with a discriminant of `0`. See [the +/// reference] for a description of how discriminant values are chosen. +/// - The type must not contain any [`UnsafeCell`]s (this is required in order +/// for it to be sound to construct a `&[u8]` and a `&T` to the same region of +/// memory). The type may contain references or pointers to `UnsafeCell`s so +/// long as those values can themselves be initialized from zeroes +/// (`FromZeroes` is not currently implemented for, e.g., +/// `Option<&UnsafeCell<_>>`, but it could be one day). +/// +/// This analysis is subject to change. Unsafe code may *only* rely on the +/// documented [safety conditions] of `FromZeroes`, and must *not* rely on the +/// implementation details of this derive. +/// +/// [the reference]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations +/// [`UnsafeCell`]: core::cell::UnsafeCell +/// +/// ## Why isn't an explicit representation required for structs? +/// +/// Neither this derive, nor the [safety conditions] of `FromZeroes`, requires +/// that structs are marked with `#[repr(C)]`. +/// +/// Per the [Rust reference](reference), +/// +/// > The representation of a type can change the padding between fields, but +/// does not change the layout of the fields themselves. +/// +/// [reference]: https://doc.rust-lang.org/reference/type-layout.html#representations +/// +/// Since the layout of structs only consists of padding bytes and field bytes, +/// a struct is soundly `FromZeroes` if: +/// 1. its padding is soundly `FromZeroes`, and +/// 2. its fields are soundly `FromZeroes`. +/// +/// The answer to the first question is always yes: padding bytes do not have +/// any validity constraints. A [discussion] of this question in the Unsafe Code +/// Guidelines Working Group concluded that it would be virtually unimaginable +/// for future versions of rustc to add validity constraints to padding bytes. +/// +/// [discussion]: https://github.com/rust-lang/unsafe-code-guidelines/issues/174 +/// +/// Whether a struct is soundly `FromZeroes` therefore solely depends on whether +/// its fields are `FromZeroes`. +// TODO(#146): Document why we don't require an enum to have an explicit `repr` +// attribute. +#[cfg(any(feature = "derive", test))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub use zerocopy_derive::FromZeroes; + +/// Types whose validity can be checked at runtime, allowing them to be +/// conditionally converted from byte slices. +/// +/// WARNING: Do not implement this trait yourself! Instead, use +/// `#[derive(TryFromBytes)]`. +/// +/// `TryFromBytes` types can safely be deserialized from an untrusted sequence +/// of bytes by performing a runtime check that the byte sequence contains a +/// valid instance of `Self`. +/// +/// `TryFromBytes` is ignorant of byte order. For byte order-aware types, see +/// the [`byteorder`] module. +/// +/// # What is a "valid instance"? +/// +/// In Rust, each type has *bit validity*, which refers to the set of bit +/// patterns which may appear in an instance of that type. It is impossible for +/// safe Rust code to produce values which violate bit validity (ie, values +/// outside of the "valid" set of bit patterns). If `unsafe` code produces an +/// invalid value, this is considered [undefined behavior]. +/// +/// Rust's bit validity rules are currently being decided, which means that some +/// types have three classes of bit patterns: those which are definitely valid, +/// and whose validity is documented in the language; those which may or may not +/// be considered valid at some point in the future; and those which are +/// definitely invalid. +/// +/// Zerocopy takes a conservative approach, and only considers a bit pattern to +/// be valid if its validity is a documenteed guarantee provided by the +/// language. +/// +/// For most use cases, Rust's current guarantees align with programmers' +/// intuitions about what ought to be valid. As a result, zerocopy's +/// conservatism should not affect most users. One notable exception is unions, +/// whose bit validity is very up in the air; zerocopy does not permit +/// implementing `TryFromBytes` for any union type. +/// +/// If you are negatively affected by lack of support for a particular type, +/// we encourage you to let us know by [filing an issue][github-repo]. +/// +/// # Safety +/// +/// On its own, `T: TryFromBytes` does not make any guarantees about the layout +/// or representation of `T`. It merely provides the ability to perform a +/// validity check at runtime via methods like [`try_from_ref`]. +/// +/// Currently, it is not possible to stably implement `TryFromBytes` other than +/// by using `#[derive(TryFromBytes)]`. While there are `#[doc(hidden)]` items +/// on this trait that provide well-defined safety invariants, no stability +/// guarantees are made with respect to these items. In particular, future +/// releases of zerocopy may make backwards-breaking changes to these items, +/// including changes that only affect soundness, which may cause code which +/// uses those items to silently become unsound. +/// +/// [undefined behavior]: https://raphlinus.github.io/programming/rust/2018/08/17/undefined-behavior.html +/// [github-repo]: https://github.com/google/zerocopy +/// [`try_from_ref`]: TryFromBytes::try_from_ref +// TODO(#5): Update `try_from_ref` doc link once it exists +#[doc(hidden)] +pub unsafe trait TryFromBytes { + /// Does a given memory range contain a valid instance of `Self`? + /// + /// # Safety + /// + /// ## Preconditions + /// + /// The memory referenced by `candidate` may only be accessed via reads for + /// the duration of this method call. This prohibits writes through mutable + /// references and through [`UnsafeCell`]s. There may exist immutable + /// references to the same memory which contain `UnsafeCell`s so long as: + /// - Those `UnsafeCell`s exist at the same byte ranges as `UnsafeCell`s in + /// `Self`. This is a bidirectional property: `Self` may not contain + /// `UnsafeCell`s where other references to the same memory do not, and + /// vice-versa. + /// - Those `UnsafeCell`s are never used to perform mutation for the + /// duration of this method call. + /// + /// The memory referenced by `candidate` may not be referenced by any + /// mutable references even if these references are not used to perform + /// mutation. + /// + /// `candidate` is not required to refer to a valid `Self`. However, it must + /// satisfy the requirement that uninitialized bytes may only be present + /// where it is possible for them to be present in `Self`. This is a dynamic + /// property: if, at a particular byte offset, a valid enum discriminant is + /// set, the subsequent bytes may only have uninitialized bytes as + /// specificed by the corresponding enum. + /// + /// Formally, given `len = size_of_val_raw(candidate)`, at every byte + /// offset, `b`, in the range `[0, len)`: + /// - If, in all instances `s: Self` of length `len`, the byte at offset `b` + /// in `s` is initialized, then the byte at offset `b` within `*candidate` + /// must be initialized. + /// - Let `c` be the contents of the byte range `[0, b)` in `*candidate`. + /// Let `S` be the subset of valid instances of `Self` of length `len` + /// which contain `c` in the offset range `[0, b)`. If, for all instances + /// of `s: Self` in `S`, the byte at offset `b` in `s` is initialized, + /// then the byte at offset `b` in `*candidate` must be initialized. + /// + /// Pragmatically, this means that if `*candidate` is guaranteed to + /// contain an enum type at a particular offset, and the enum discriminant + /// stored in `*candidate` corresponds to a valid variant of that enum + /// type, then it is guaranteed that the appropriate bytes of `*candidate` + /// are initialized as defined by that variant's bit validity (although + /// note that the variant may contain another enum type, in which case the + /// same rules apply depending on the state of its discriminant, and so on + /// recursively). + /// + /// ## Postconditions + /// + /// Unsafe code may assume that, if `is_bit_valid(candidate)` returns true, + /// `*candidate` contains a valid `Self`. + /// + /// # Panics + /// + /// `is_bit_valid` may panic. Callers are responsible for ensuring that any + /// `unsafe` code remains sound even in the face of `is_bit_valid` + /// panicking. (We support user-defined validation routines; so long as + /// these routines are not required to be `unsafe`, there is no way to + /// ensure that these do not generate panics.) + /// + /// [`UnsafeCell`]: core::cell::UnsafeCell + #[doc(hidden)] + unsafe fn is_bit_valid(candidate: Ptr<'_, Self>) -> bool; + + /// Attempts to interpret a byte slice as a `Self`. + /// + /// `try_from_ref` validates that `bytes` contains a valid `Self`, and that + /// it satisfies `Self`'s alignment requirement. If it does, then `bytes` is + /// reinterpreted as a `Self`. + /// + /// Note that Rust's bit validity rules are still being decided. As such, + /// there exist types whose bit validity is ambiguous. See the + /// `TryFromBytes` docs for a discussion of how these cases are handled. + // TODO(#251): In a future in which we distinguish between `FromBytes` and + // `RefFromBytes`, this requires `where Self: RefFromBytes` to disallow + // interior mutability. + #[inline] + #[doc(hidden)] // TODO(#5): Finalize name before remove this attribute. + fn try_from_ref(bytes: &[u8]) -> Option<&Self> + where + Self: KnownLayout, + { + let maybe_self = Ptr::from(bytes).try_cast_into_no_leftover::()?; + + // SAFETY: + // - Since `bytes` is an immutable reference, we know that no mutable + // references exist to this memory region. + // - Since `[u8]` contains no `UnsafeCell`s, we know there are no + // `&UnsafeCell` references to this memory region. + // - Since we don't permit implementing `TryFromBytes` for types which + // contain `UnsafeCell`s, there are no `UnsafeCell`s in `Self`, and so + // the requirement that all references contain `UnsafeCell`s at the + // same offsets is trivially satisfied. + // - All bytes of `bytes` are initialized. + // + // This call may panic. If that happens, it doesn't cause any soundness + // issues, as we have not generated any invalid state which we need to + // fix before returning. + if unsafe { !Self::is_bit_valid(maybe_self) } { + return None; + } + + // SAFETY: + // - Preconditions for `as_ref`: + // - `is_bit_valid` guarantees that `*maybe_self` contains a valid + // `Self`. Since `&[u8]` does not permit interior mutation, this + // cannot be invalidated after this method returns. + // - Since the argument and return types are immutable references, + // Rust will prevent the caller from producing any mutable + // references to the same memory region. + // - Since `Self` is not allowed to contain any `UnsafeCell`s and the + // same is true of `[u8]`, interior mutation is not possible. Thus, + // no mutation is possible. For the same reason, there is no + // mismatch between the two types in terms of which byte ranges are + // referenced as `UnsafeCell`s. + // - Since interior mutation isn't possible within `Self`, there's no + // way for the returned reference to be used to modify the byte range, + // and thus there's no way for the returned reference to be used to + // write an invalid `[u8]` which would be observable via the original + // `&[u8]`. + Some(unsafe { maybe_self.as_ref() }) + } +} + +/// Types for which a sequence of bytes all set to zero represents a valid +/// instance of the type. +/// +/// Any memory region of the appropriate length which is guaranteed to contain +/// only zero bytes can be viewed as any `FromZeroes` type with no runtime +/// overhead. This is useful whenever memory is known to be in a zeroed state, +/// such memory returned from some allocation routines. +/// +/// # Implementation +/// +/// **Do not implement this trait yourself!** Instead, use +/// [`#[derive(FromZeroes)]`][derive] (requires the `derive` Cargo feature); +/// e.g.: +/// +/// ``` +/// # use zerocopy_derive::FromZeroes; +/// #[derive(FromZeroes)] +/// struct MyStruct { +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes)] +/// #[repr(u8)] +/// enum MyEnum { +/// # Variant0, +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes)] +/// union MyUnion { +/// # variant: u8, +/// # /* +/// ... +/// # */ +/// } +/// ``` +/// +/// This derive performs a sophisticated, compile-time safety analysis to +/// determine whether a type is `FromZeroes`. +/// +/// # Safety +/// +/// *This section describes what is required in order for `T: FromZeroes`, and +/// what unsafe code may assume of such types. If you don't plan on implementing +/// `FromZeroes` manually, and you don't plan on writing unsafe code that +/// operates on `FromZeroes` types, then you don't need to read this section.* +/// +/// If `T: FromZeroes`, then unsafe code may assume that: +/// - It is sound to treat any initialized sequence of zero bytes of length +/// `size_of::()` as a `T`. +/// - Given `b: &[u8]` where `b.len() == size_of::()`, `b` is aligned to +/// `align_of::()`, and `b` contains only zero bytes, it is sound to +/// construct a `t: &T` at the same address as `b`, and it is sound for both +/// `b` and `t` to be live at the same time. +/// +/// If a type is marked as `FromZeroes` which violates this contract, it may +/// cause undefined behavior. +/// +/// `#[derive(FromZeroes)]` only permits [types which satisfy these +/// requirements][derive-analysis]. +/// +#[cfg_attr( + feature = "derive", + doc = "[derive]: zerocopy_derive::FromZeroes", + doc = "[derive-analysis]: zerocopy_derive::FromZeroes#analysis" +)] +#[cfg_attr( + not(feature = "derive"), + doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeroes.html"), + doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromZeroes.html#analysis"), +)] +pub unsafe trait FromZeroes { + // The `Self: Sized` bound makes it so that `FromZeroes` is still object + // safe. + #[doc(hidden)] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized; + + /// Overwrites `self` with zeroes. + /// + /// Sets every byte in `self` to 0. While this is similar to doing `*self = + /// Self::new_zeroed()`, it differs in that `zero` does not semantically + /// drop the current value and replace it with a new one - it simply + /// modifies the bytes of the existing value. + /// + /// # Examples + /// + /// ``` + /// # use zerocopy::FromZeroes; + /// # use zerocopy_derive::*; + /// # + /// #[derive(FromZeroes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let mut header = PacketHeader { + /// src_port: 100u16.to_be_bytes(), + /// dst_port: 200u16.to_be_bytes(), + /// length: 300u16.to_be_bytes(), + /// checksum: 400u16.to_be_bytes(), + /// }; + /// + /// header.zero(); + /// + /// assert_eq!(header.src_port, [0, 0]); + /// assert_eq!(header.dst_port, [0, 0]); + /// assert_eq!(header.length, [0, 0]); + /// assert_eq!(header.checksum, [0, 0]); + /// ``` + #[inline(always)] + fn zero(&mut self) { + let slf: *mut Self = self; + let len = mem::size_of_val(self); + // SAFETY: + // - `self` is guaranteed by the type system to be valid for writes of + // size `size_of_val(self)`. + // - `u8`'s alignment is 1, and thus `self` is guaranteed to be aligned + // as required by `u8`. + // - Since `Self: FromZeroes`, the all-zeroes instance is a valid + // instance of `Self.` + // + // TODO(#429): Add references to docs and quotes. + unsafe { ptr::write_bytes(slf.cast::(), 0, len) }; + } + + /// Creates an instance of `Self` from zeroed bytes. + /// + /// # Examples + /// + /// ``` + /// # use zerocopy::FromZeroes; + /// # use zerocopy_derive::*; + /// # + /// #[derive(FromZeroes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let header: PacketHeader = FromZeroes::new_zeroed(); + /// + /// assert_eq!(header.src_port, [0, 0]); + /// assert_eq!(header.dst_port, [0, 0]); + /// assert_eq!(header.length, [0, 0]); + /// assert_eq!(header.checksum, [0, 0]); + /// ``` + #[inline(always)] + fn new_zeroed() -> Self + where + Self: Sized, + { + // SAFETY: `FromZeroes` says that the all-zeroes bit pattern is legal. + unsafe { mem::zeroed() } + } + + /// Creates a `Box` from zeroed bytes. + /// + /// This function is useful for allocating large values on the heap and + /// zero-initializing them, without ever creating a temporary instance of + /// `Self` on the stack. For example, `<[u8; 1048576]>::new_box_zeroed()` + /// will allocate `[u8; 1048576]` directly on the heap; it does not require + /// storing `[u8; 1048576]` in a temporary variable on the stack. + /// + /// On systems that use a heap implementation that supports allocating from + /// pre-zeroed memory, using `new_box_zeroed` (or related functions) may + /// have performance benefits. + /// + /// Note that `Box` can be converted to `Arc` and other + /// container types without reallocation. + /// + /// # Panics + /// + /// Panics if allocation of `size_of::()` bytes fails. + #[cfg(feature = "alloc")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] + #[inline] + fn new_box_zeroed() -> Box + where + Self: Sized, + { + // If `T` is a ZST, then return a proper boxed instance of it. There is + // no allocation, but `Box` does require a correct dangling pointer. + let layout = Layout::new::(); + if layout.size() == 0 { + return Box::new(Self::new_zeroed()); + } + + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + let ptr = unsafe { alloc::alloc::alloc_zeroed(layout).cast::() }; + if ptr.is_null() { + alloc::alloc::handle_alloc_error(layout); + } + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + unsafe { + Box::from_raw(ptr) + } + } + + /// Creates a `Box<[Self]>` (a boxed slice) from zeroed bytes. + /// + /// This function is useful for allocating large values of `[Self]` on the + /// heap and zero-initializing them, without ever creating a temporary + /// instance of `[Self; _]` on the stack. For example, + /// `u8::new_box_slice_zeroed(1048576)` will allocate the slice directly on + /// the heap; it does not require storing the slice on the stack. + /// + /// On systems that use a heap implementation that supports allocating from + /// pre-zeroed memory, using `new_box_slice_zeroed` may have performance + /// benefits. + /// + /// If `Self` is a zero-sized type, then this function will return a + /// `Box<[Self]>` that has the correct `len`. Such a box cannot contain any + /// actual information, but its `len()` property will report the correct + /// value. + /// + /// # Panics + /// + /// * Panics if `size_of::() * len` overflows. + /// * Panics if allocation of `size_of::() * len` bytes fails. + #[cfg(feature = "alloc")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] + #[inline] + fn new_box_slice_zeroed(len: usize) -> Box<[Self]> + where + Self: Sized, + { + let size = mem::size_of::() + .checked_mul(len) + .expect("mem::size_of::() * len overflows `usize`"); + let align = mem::align_of::(); + // On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a + // bug in which sufficiently-large allocations (those which, when + // rounded up to the alignment, overflow `isize`) are not rejected, + // which can cause undefined behavior. See #64 for details. + // + // TODO(#67): Once our MSRV is > 1.64.0, remove this assertion. + #[allow(clippy::as_conversions)] + let max_alloc = (isize::MAX as usize).saturating_sub(align); + assert!(size <= max_alloc); + // TODO(https://github.com/rust-lang/rust/issues/55724): Use + // `Layout::repeat` once it's stabilized. + let layout = + Layout::from_size_align(size, align).expect("total allocation size overflows `isize`"); + + let ptr = if layout.size() != 0 { + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + let ptr = unsafe { alloc::alloc::alloc_zeroed(layout).cast::() }; + if ptr.is_null() { + alloc::alloc::handle_alloc_error(layout); + } + ptr + } else { + // `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. + NonNull::::dangling().as_ptr() + }; + + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + unsafe { + Box::from_raw(slice::from_raw_parts_mut(ptr, len)) + } + } + + /// Creates a `Vec` from zeroed bytes. + /// + /// This function is useful for allocating large values of `Vec`s and + /// zero-initializing them, without ever creating a temporary instance of + /// `[Self; _]` (or many temporary instances of `Self`) on the stack. For + /// example, `u8::new_vec_zeroed(1048576)` will allocate directly on the + /// heap; it does not require storing intermediate values on the stack. + /// + /// On systems that use a heap implementation that supports allocating from + /// pre-zeroed memory, using `new_vec_zeroed` may have performance benefits. + /// + /// If `Self` is a zero-sized type, then this function will return a + /// `Vec` that has the correct `len`. Such a `Vec` cannot contain any + /// actual information, but its `len()` property will report the correct + /// value. + /// + /// # Panics + /// + /// * Panics if `size_of::() * len` overflows. + /// * Panics if allocation of `size_of::() * len` bytes fails. + #[cfg(feature = "alloc")] + #[cfg_attr(doc_cfg, doc(cfg(feature = "new_vec_zeroed")))] + #[inline(always)] + fn new_vec_zeroed(len: usize) -> Vec + where + Self: Sized, + { + Self::new_box_slice_zeroed(len).into() + } +} + +/// Analyzes whether a type is [`FromBytes`]. +/// +/// This derive analyzes, at compile time, whether the annotated type satisfies +/// the [safety conditions] of `FromBytes` and implements `FromBytes` if it is +/// sound to do so. This derive can be applied to structs, enums, and unions; +/// e.g.: +/// +/// ``` +/// # use zerocopy_derive::{FromBytes, FromZeroes}; +/// #[derive(FromZeroes, FromBytes)] +/// struct MyStruct { +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes, FromBytes)] +/// #[repr(u8)] +/// enum MyEnum { +/// # V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, V0A, V0B, V0C, V0D, V0E, +/// # V0F, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V1A, V1B, V1C, V1D, +/// # V1E, V1F, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V2A, V2B, V2C, +/// # V2D, V2E, V2F, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V3A, V3B, +/// # V3C, V3D, V3E, V3F, V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, V4A, +/// # V4B, V4C, V4D, V4E, V4F, V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, +/// # V5A, V5B, V5C, V5D, V5E, V5F, V60, V61, V62, V63, V64, V65, V66, V67, V68, +/// # V69, V6A, V6B, V6C, V6D, V6E, V6F, V70, V71, V72, V73, V74, V75, V76, V77, +/// # V78, V79, V7A, V7B, V7C, V7D, V7E, V7F, V80, V81, V82, V83, V84, V85, V86, +/// # V87, V88, V89, V8A, V8B, V8C, V8D, V8E, V8F, V90, V91, V92, V93, V94, V95, +/// # V96, V97, V98, V99, V9A, V9B, V9C, V9D, V9E, V9F, VA0, VA1, VA2, VA3, VA4, +/// # VA5, VA6, VA7, VA8, VA9, VAA, VAB, VAC, VAD, VAE, VAF, VB0, VB1, VB2, VB3, +/// # VB4, VB5, VB6, VB7, VB8, VB9, VBA, VBB, VBC, VBD, VBE, VBF, VC0, VC1, VC2, +/// # VC3, VC4, VC5, VC6, VC7, VC8, VC9, VCA, VCB, VCC, VCD, VCE, VCF, VD0, VD1, +/// # VD2, VD3, VD4, VD5, VD6, VD7, VD8, VD9, VDA, VDB, VDC, VDD, VDE, VDF, VE0, +/// # VE1, VE2, VE3, VE4, VE5, VE6, VE7, VE8, VE9, VEA, VEB, VEC, VED, VEE, VEF, +/// # VF0, VF1, VF2, VF3, VF4, VF5, VF6, VF7, VF8, VF9, VFA, VFB, VFC, VFD, VFE, +/// # VFF, +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes, FromBytes)] +/// union MyUnion { +/// # variant: u8, +/// # /* +/// ... +/// # */ +/// } +/// ``` +/// +/// [safety conditions]: trait@FromBytes#safety +/// +/// # Analysis +/// +/// *This section describes, roughly, the analysis performed by this derive to +/// determine whether it is sound to implement `FromBytes` for a given type. +/// Unless you are modifying the implementation of this derive, or attempting to +/// manually implement `FromBytes` for a type yourself, you don't need to read +/// this section.* +/// +/// If a type has the following properties, then this derive can implement +/// `FromBytes` for that type: +/// +/// - If the type is a struct, all of its fields must be `FromBytes`. +/// - If the type is an enum: +/// - It must be a C-like enum (meaning that all variants have no fields). +/// - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`, +/// `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`). +/// - The maximum number of discriminants must be used (so that every possible +/// bit pattern is a valid one). Be very careful when using the `C`, +/// `usize`, or `isize` representations, as their size is +/// platform-dependent. +/// - The type must not contain any [`UnsafeCell`]s (this is required in order +/// for it to be sound to construct a `&[u8]` and a `&T` to the same region of +/// memory). The type may contain references or pointers to `UnsafeCell`s so +/// long as those values can themselves be initialized from zeroes +/// (`FromBytes` is not currently implemented for, e.g., `Option<*const +/// UnsafeCell<_>>`, but it could be one day). +/// +/// [`UnsafeCell`]: core::cell::UnsafeCell +/// +/// This analysis is subject to change. Unsafe code may *only* rely on the +/// documented [safety conditions] of `FromBytes`, and must *not* rely on the +/// implementation details of this derive. +/// +/// ## Why isn't an explicit representation required for structs? +/// +/// Neither this derive, nor the [safety conditions] of `FromBytes`, requires +/// that structs are marked with `#[repr(C)]`. +/// +/// Per the [Rust reference](reference), +/// +/// > The representation of a type can change the padding between fields, but +/// does not change the layout of the fields themselves. +/// +/// [reference]: https://doc.rust-lang.org/reference/type-layout.html#representations +/// +/// Since the layout of structs only consists of padding bytes and field bytes, +/// a struct is soundly `FromBytes` if: +/// 1. its padding is soundly `FromBytes`, and +/// 2. its fields are soundly `FromBytes`. +/// +/// The answer to the first question is always yes: padding bytes do not have +/// any validity constraints. A [discussion] of this question in the Unsafe Code +/// Guidelines Working Group concluded that it would be virtually unimaginable +/// for future versions of rustc to add validity constraints to padding bytes. +/// +/// [discussion]: https://github.com/rust-lang/unsafe-code-guidelines/issues/174 +/// +/// Whether a struct is soundly `FromBytes` therefore solely depends on whether +/// its fields are `FromBytes`. +// TODO(#146): Document why we don't require an enum to have an explicit `repr` +// attribute. +#[cfg(any(feature = "derive", test))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub use zerocopy_derive::FromBytes; + +/// Types for which any bit pattern is valid. +/// +/// Any memory region of the appropriate length which contains initialized bytes +/// can be viewed as any `FromBytes` type with no runtime overhead. This is +/// useful for efficiently parsing bytes as structured data. +/// +/// # Implementation +/// +/// **Do not implement this trait yourself!** Instead, use +/// [`#[derive(FromBytes)]`][derive] (requires the `derive` Cargo feature); +/// e.g.: +/// +/// ``` +/// # use zerocopy_derive::{FromBytes, FromZeroes}; +/// #[derive(FromZeroes, FromBytes)] +/// struct MyStruct { +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes, FromBytes)] +/// #[repr(u8)] +/// enum MyEnum { +/// # V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, V0A, V0B, V0C, V0D, V0E, +/// # V0F, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V1A, V1B, V1C, V1D, +/// # V1E, V1F, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V2A, V2B, V2C, +/// # V2D, V2E, V2F, V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, V3A, V3B, +/// # V3C, V3D, V3E, V3F, V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, V4A, +/// # V4B, V4C, V4D, V4E, V4F, V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, +/// # V5A, V5B, V5C, V5D, V5E, V5F, V60, V61, V62, V63, V64, V65, V66, V67, V68, +/// # V69, V6A, V6B, V6C, V6D, V6E, V6F, V70, V71, V72, V73, V74, V75, V76, V77, +/// # V78, V79, V7A, V7B, V7C, V7D, V7E, V7F, V80, V81, V82, V83, V84, V85, V86, +/// # V87, V88, V89, V8A, V8B, V8C, V8D, V8E, V8F, V90, V91, V92, V93, V94, V95, +/// # V96, V97, V98, V99, V9A, V9B, V9C, V9D, V9E, V9F, VA0, VA1, VA2, VA3, VA4, +/// # VA5, VA6, VA7, VA8, VA9, VAA, VAB, VAC, VAD, VAE, VAF, VB0, VB1, VB2, VB3, +/// # VB4, VB5, VB6, VB7, VB8, VB9, VBA, VBB, VBC, VBD, VBE, VBF, VC0, VC1, VC2, +/// # VC3, VC4, VC5, VC6, VC7, VC8, VC9, VCA, VCB, VCC, VCD, VCE, VCF, VD0, VD1, +/// # VD2, VD3, VD4, VD5, VD6, VD7, VD8, VD9, VDA, VDB, VDC, VDD, VDE, VDF, VE0, +/// # VE1, VE2, VE3, VE4, VE5, VE6, VE7, VE8, VE9, VEA, VEB, VEC, VED, VEE, VEF, +/// # VF0, VF1, VF2, VF3, VF4, VF5, VF6, VF7, VF8, VF9, VFA, VFB, VFC, VFD, VFE, +/// # VFF, +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(FromZeroes, FromBytes)] +/// union MyUnion { +/// # variant: u8, +/// # /* +/// ... +/// # */ +/// } +/// ``` +/// +/// This derive performs a sophisticated, compile-time safety analysis to +/// determine whether a type is `FromBytes`. +/// +/// # Safety +/// +/// *This section describes what is required in order for `T: FromBytes`, and +/// what unsafe code may assume of such types. If you don't plan on implementing +/// `FromBytes` manually, and you don't plan on writing unsafe code that +/// operates on `FromBytes` types, then you don't need to read this section.* +/// +/// If `T: FromBytes`, then unsafe code may assume that: +/// - It is sound to treat any initialized sequence of bytes of length +/// `size_of::()` as a `T`. +/// - Given `b: &[u8]` where `b.len() == size_of::()`, `b` is aligned to +/// `align_of::()` it is sound to construct a `t: &T` at the same address +/// as `b`, and it is sound for both `b` and `t` to be live at the same time. +/// +/// If a type is marked as `FromBytes` which violates this contract, it may +/// cause undefined behavior. +/// +/// `#[derive(FromBytes)]` only permits [types which satisfy these +/// requirements][derive-analysis]. +/// +#[cfg_attr( + feature = "derive", + doc = "[derive]: zerocopy_derive::FromBytes", + doc = "[derive-analysis]: zerocopy_derive::FromBytes#analysis" +)] +#[cfg_attr( + not(feature = "derive"), + doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromBytes.html"), + doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.FromBytes.html#analysis"), +)] +pub unsafe trait FromBytes: FromZeroes { + // The `Self: Sized` bound makes it so that `FromBytes` is still object + // safe. + #[doc(hidden)] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized; + + /// Interprets the given `bytes` as a `&Self` without copying. + /// + /// If `bytes.len() != size_of::()` or `bytes` is not aligned to + /// `align_of::()`, this returns `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// // These bytes encode a `PacketHeader`. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7].as_slice(); + /// + /// let header = PacketHeader::ref_from(bytes).unwrap(); + /// + /// assert_eq!(header.src_port, [0, 1]); + /// assert_eq!(header.dst_port, [2, 3]); + /// assert_eq!(header.length, [4, 5]); + /// assert_eq!(header.checksum, [6, 7]); + /// ``` + #[inline] + fn ref_from(bytes: &[u8]) -> Option<&Self> + where + Self: Sized, + { + Ref::<&[u8], Self>::new(bytes).map(Ref::into_ref) + } + + /// Interprets the prefix of the given `bytes` as a `&Self` without copying. + /// + /// `ref_from_prefix` returns a reference to the first `size_of::()` + /// bytes of `bytes`. If `bytes.len() < size_of::()` or `bytes` is not + /// aligned to `align_of::()`, this returns `None`. + /// + /// To also access the prefix bytes, use [`Ref::new_from_prefix`]. Then, use + /// [`Ref::into_ref`] to get a `&Self` with the same lifetime. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// // These are more bytes than are needed to encode a `PacketHeader`. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice(); + /// + /// let header = PacketHeader::ref_from_prefix(bytes).unwrap(); + /// + /// assert_eq!(header.src_port, [0, 1]); + /// assert_eq!(header.dst_port, [2, 3]); + /// assert_eq!(header.length, [4, 5]); + /// assert_eq!(header.checksum, [6, 7]); + /// ``` + #[inline] + fn ref_from_prefix(bytes: &[u8]) -> Option<&Self> + where + Self: Sized, + { + Ref::<&[u8], Self>::new_from_prefix(bytes).map(|(r, _)| r.into_ref()) + } + + /// Interprets the suffix of the given `bytes` as a `&Self` without copying. + /// + /// `ref_from_suffix` returns a reference to the last `size_of::()` + /// bytes of `bytes`. If `bytes.len() < size_of::()` or the suffix of + /// `bytes` is not aligned to `align_of::()`, this returns `None`. + /// + /// To also access the suffix bytes, use [`Ref::new_from_suffix`]. Then, use + /// [`Ref::into_ref`] to get a `&Self` with the same lifetime. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketTrailer { + /// frame_check_sequence: [u8; 4], + /// } + /// + /// // These are more bytes than are needed to encode a `PacketTrailer`. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice(); + /// + /// let trailer = PacketTrailer::ref_from_suffix(bytes).unwrap(); + /// + /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]); + /// ``` + #[inline] + fn ref_from_suffix(bytes: &[u8]) -> Option<&Self> + where + Self: Sized, + { + Ref::<&[u8], Self>::new_from_suffix(bytes).map(|(_, r)| r.into_ref()) + } + + /// Interprets the given `bytes` as a `&mut Self` without copying. + /// + /// If `bytes.len() != size_of::()` or `bytes` is not aligned to + /// `align_of::()`, this returns `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// // These bytes encode a `PacketHeader`. + /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7][..]; + /// + /// let header = PacketHeader::mut_from(bytes).unwrap(); + /// + /// assert_eq!(header.src_port, [0, 1]); + /// assert_eq!(header.dst_port, [2, 3]); + /// assert_eq!(header.length, [4, 5]); + /// assert_eq!(header.checksum, [6, 7]); + /// + /// header.checksum = [0, 0]; + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0]); + /// ``` + #[inline] + fn mut_from(bytes: &mut [u8]) -> Option<&mut Self> + where + Self: Sized + AsBytes, + { + Ref::<&mut [u8], Self>::new(bytes).map(Ref::into_mut) + } + + /// Interprets the prefix of the given `bytes` as a `&mut Self` without + /// copying. + /// + /// `mut_from_prefix` returns a reference to the first `size_of::()` + /// bytes of `bytes`. If `bytes.len() < size_of::()` or `bytes` is not + /// aligned to `align_of::()`, this returns `None`. + /// + /// To also access the prefix bytes, use [`Ref::new_from_prefix`]. Then, use + /// [`Ref::into_mut`] to get a `&mut Self` with the same lifetime. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// // These are more bytes than are needed to encode a `PacketHeader`. + /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; + /// + /// let header = PacketHeader::mut_from_prefix(bytes).unwrap(); + /// + /// assert_eq!(header.src_port, [0, 1]); + /// assert_eq!(header.dst_port, [2, 3]); + /// assert_eq!(header.length, [4, 5]); + /// assert_eq!(header.checksum, [6, 7]); + /// + /// header.checksum = [0, 0]; + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 8, 9]); + /// ``` + #[inline] + fn mut_from_prefix(bytes: &mut [u8]) -> Option<&mut Self> + where + Self: Sized + AsBytes, + { + Ref::<&mut [u8], Self>::new_from_prefix(bytes).map(|(r, _)| r.into_mut()) + } + + /// Interprets the suffix of the given `bytes` as a `&mut Self` without copying. + /// + /// `mut_from_suffix` returns a reference to the last `size_of::()` + /// bytes of `bytes`. If `bytes.len() < size_of::()` or the suffix of + /// `bytes` is not aligned to `align_of::()`, this returns `None`. + /// + /// To also access the suffix bytes, use [`Ref::new_from_suffix`]. Then, + /// use [`Ref::into_mut`] to get a `&mut Self` with the same lifetime. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketTrailer { + /// frame_check_sequence: [u8; 4], + /// } + /// + /// // These are more bytes than are needed to encode a `PacketTrailer`. + /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; + /// + /// let trailer = PacketTrailer::mut_from_suffix(bytes).unwrap(); + /// + /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]); + /// + /// trailer.frame_check_sequence = [0, 0, 0, 0]; + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 0, 0]); + /// ``` + #[inline] + fn mut_from_suffix(bytes: &mut [u8]) -> Option<&mut Self> + where + Self: Sized + AsBytes, + { + Ref::<&mut [u8], Self>::new_from_suffix(bytes).map(|(_, r)| r.into_mut()) + } + + /// Interprets the given `bytes` as a `&[Self]` without copying. + /// + /// If `bytes.len() % size_of::() != 0` or `bytes` is not aligned to + /// `align_of::()`, this returns `None`. + /// + /// If you need to convert a specific number of slice elements, see + /// [`slice_from_prefix`](FromBytes::slice_from_prefix) or + /// [`slice_from_suffix`](FromBytes::slice_from_suffix). + /// + /// # Panics + /// + /// If `Self` is a zero-sized type. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Debug, PartialEq, Eq)] + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct Pixel { + /// r: u8, + /// g: u8, + /// b: u8, + /// a: u8, + /// } + /// + /// // These bytes encode two `Pixel`s. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7].as_slice(); + /// + /// let pixels = Pixel::slice_from(bytes).unwrap(); + /// + /// assert_eq!(pixels, &[ + /// Pixel { r: 0, g: 1, b: 2, a: 3 }, + /// Pixel { r: 4, g: 5, b: 6, a: 7 }, + /// ]); + /// ``` + #[inline] + fn slice_from(bytes: &[u8]) -> Option<&[Self]> + where + Self: Sized, + { + Ref::<_, [Self]>::new_slice(bytes).map(|r| r.into_slice()) + } + + /// Interprets the prefix of the given `bytes` as a `&[Self]` with length + /// equal to `count` without copying. + /// + /// This method verifies that `bytes.len() >= size_of::() * count` + /// and that `bytes` is aligned to `align_of::()`. It consumes the + /// first `size_of::() * count` bytes from `bytes` to construct a + /// `&[Self]`, and returns the remaining bytes to the caller. It also + /// ensures that `sizeof::() * count` does not overflow a `usize`. + /// If any of the length, alignment, or overflow checks fail, it returns + /// `None`. + /// + /// # Panics + /// + /// If `T` is a zero-sized type. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Debug, PartialEq, Eq)] + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct Pixel { + /// r: u8, + /// g: u8, + /// b: u8, + /// a: u8, + /// } + /// + /// // These are more bytes than are needed to encode two `Pixel`s. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice(); + /// + /// let (pixels, rest) = Pixel::slice_from_prefix(bytes, 2).unwrap(); + /// + /// assert_eq!(pixels, &[ + /// Pixel { r: 0, g: 1, b: 2, a: 3 }, + /// Pixel { r: 4, g: 5, b: 6, a: 7 }, + /// ]); + /// + /// assert_eq!(rest, &[8, 9]); + /// ``` + #[inline] + fn slice_from_prefix(bytes: &[u8], count: usize) -> Option<(&[Self], &[u8])> + where + Self: Sized, + { + Ref::<_, [Self]>::new_slice_from_prefix(bytes, count).map(|(r, b)| (r.into_slice(), b)) + } + + /// Interprets the suffix of the given `bytes` as a `&[Self]` with length + /// equal to `count` without copying. + /// + /// This method verifies that `bytes.len() >= size_of::() * count` + /// and that `bytes` is aligned to `align_of::()`. It consumes the + /// last `size_of::() * count` bytes from `bytes` to construct a + /// `&[Self]`, and returns the preceding bytes to the caller. It also + /// ensures that `sizeof::() * count` does not overflow a `usize`. + /// If any of the length, alignment, or overflow checks fail, it returns + /// `None`. + /// + /// # Panics + /// + /// If `T` is a zero-sized type. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Debug, PartialEq, Eq)] + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct Pixel { + /// r: u8, + /// g: u8, + /// b: u8, + /// a: u8, + /// } + /// + /// // These are more bytes than are needed to encode two `Pixel`s. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice(); + /// + /// let (rest, pixels) = Pixel::slice_from_suffix(bytes, 2).unwrap(); + /// + /// assert_eq!(rest, &[0, 1]); + /// + /// assert_eq!(pixels, &[ + /// Pixel { r: 2, g: 3, b: 4, a: 5 }, + /// Pixel { r: 6, g: 7, b: 8, a: 9 }, + /// ]); + /// ``` + #[inline] + fn slice_from_suffix(bytes: &[u8], count: usize) -> Option<(&[u8], &[Self])> + where + Self: Sized, + { + Ref::<_, [Self]>::new_slice_from_suffix(bytes, count).map(|(b, r)| (b, r.into_slice())) + } + + /// Interprets the given `bytes` as a `&mut [Self]` without copying. + /// + /// If `bytes.len() % size_of::() != 0` or `bytes` is not aligned to + /// `align_of::()`, this returns `None`. + /// + /// If you need to convert a specific number of slice elements, see + /// [`mut_slice_from_prefix`](FromBytes::mut_slice_from_prefix) or + /// [`mut_slice_from_suffix`](FromBytes::mut_slice_from_suffix). + /// + /// # Panics + /// + /// If `T` is a zero-sized type. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Debug, PartialEq, Eq)] + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct Pixel { + /// r: u8, + /// g: u8, + /// b: u8, + /// a: u8, + /// } + /// + /// // These bytes encode two `Pixel`s. + /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7][..]; + /// + /// let pixels = Pixel::mut_slice_from(bytes).unwrap(); + /// + /// assert_eq!(pixels, &[ + /// Pixel { r: 0, g: 1, b: 2, a: 3 }, + /// Pixel { r: 4, g: 5, b: 6, a: 7 }, + /// ]); + /// + /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 }; + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0]); + /// ``` + #[inline] + fn mut_slice_from(bytes: &mut [u8]) -> Option<&mut [Self]> + where + Self: Sized + AsBytes, + { + Ref::<_, [Self]>::new_slice(bytes).map(|r| r.into_mut_slice()) + } + + /// Interprets the prefix of the given `bytes` as a `&mut [Self]` with length + /// equal to `count` without copying. + /// + /// This method verifies that `bytes.len() >= size_of::() * count` + /// and that `bytes` is aligned to `align_of::()`. It consumes the + /// first `size_of::() * count` bytes from `bytes` to construct a + /// `&[Self]`, and returns the remaining bytes to the caller. It also + /// ensures that `sizeof::() * count` does not overflow a `usize`. + /// If any of the length, alignment, or overflow checks fail, it returns + /// `None`. + /// + /// # Panics + /// + /// If `T` is a zero-sized type. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Debug, PartialEq, Eq)] + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct Pixel { + /// r: u8, + /// g: u8, + /// b: u8, + /// a: u8, + /// } + /// + /// // These are more bytes than are needed to encode two `Pixel`s. + /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; + /// + /// let (pixels, rest) = Pixel::mut_slice_from_prefix(bytes, 2).unwrap(); + /// + /// assert_eq!(pixels, &[ + /// Pixel { r: 0, g: 1, b: 2, a: 3 }, + /// Pixel { r: 4, g: 5, b: 6, a: 7 }, + /// ]); + /// + /// assert_eq!(rest, &[8, 9]); + /// + /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 }; + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0, 8, 9]); + /// ``` + #[inline] + fn mut_slice_from_prefix(bytes: &mut [u8], count: usize) -> Option<(&mut [Self], &mut [u8])> + where + Self: Sized + AsBytes, + { + Ref::<_, [Self]>::new_slice_from_prefix(bytes, count).map(|(r, b)| (r.into_mut_slice(), b)) + } + + /// Interprets the suffix of the given `bytes` as a `&mut [Self]` with length + /// equal to `count` without copying. + /// + /// This method verifies that `bytes.len() >= size_of::() * count` + /// and that `bytes` is aligned to `align_of::()`. It consumes the + /// last `size_of::() * count` bytes from `bytes` to construct a + /// `&[Self]`, and returns the preceding bytes to the caller. It also + /// ensures that `sizeof::() * count` does not overflow a `usize`. + /// If any of the length, alignment, or overflow checks fail, it returns + /// `None`. + /// + /// # Panics + /// + /// If `T` is a zero-sized type. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Debug, PartialEq, Eq)] + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct Pixel { + /// r: u8, + /// g: u8, + /// b: u8, + /// a: u8, + /// } + /// + /// // These are more bytes than are needed to encode two `Pixel`s. + /// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; + /// + /// let (rest, pixels) = Pixel::mut_slice_from_suffix(bytes, 2).unwrap(); + /// + /// assert_eq!(rest, &[0, 1]); + /// + /// assert_eq!(pixels, &[ + /// Pixel { r: 2, g: 3, b: 4, a: 5 }, + /// Pixel { r: 6, g: 7, b: 8, a: 9 }, + /// ]); + /// + /// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 }; + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 0, 0]); + /// ``` + #[inline] + fn mut_slice_from_suffix(bytes: &mut [u8], count: usize) -> Option<(&mut [u8], &mut [Self])> + where + Self: Sized + AsBytes, + { + Ref::<_, [Self]>::new_slice_from_suffix(bytes, count).map(|(b, r)| (b, r.into_mut_slice())) + } + + /// Reads a copy of `Self` from `bytes`. + /// + /// If `bytes.len() != size_of::()`, `read_from` returns `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// // These bytes encode a `PacketHeader`. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7].as_slice(); + /// + /// let header = PacketHeader::read_from(bytes).unwrap(); + /// + /// assert_eq!(header.src_port, [0, 1]); + /// assert_eq!(header.dst_port, [2, 3]); + /// assert_eq!(header.length, [4, 5]); + /// assert_eq!(header.checksum, [6, 7]); + /// ``` + #[inline] + fn read_from(bytes: &[u8]) -> Option + where + Self: Sized, + { + Ref::<_, Unalign>::new_unaligned(bytes).map(|r| r.read().into_inner()) + } + + /// Reads a copy of `Self` from the prefix of `bytes`. + /// + /// `read_from_prefix` reads a `Self` from the first `size_of::()` + /// bytes of `bytes`. If `bytes.len() < size_of::()`, it returns + /// `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// // These are more bytes than are needed to encode a `PacketHeader`. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice(); + /// + /// let header = PacketHeader::read_from_prefix(bytes).unwrap(); + /// + /// assert_eq!(header.src_port, [0, 1]); + /// assert_eq!(header.dst_port, [2, 3]); + /// assert_eq!(header.length, [4, 5]); + /// assert_eq!(header.checksum, [6, 7]); + /// ``` + #[inline] + fn read_from_prefix(bytes: &[u8]) -> Option + where + Self: Sized, + { + Ref::<_, Unalign>::new_unaligned_from_prefix(bytes) + .map(|(r, _)| r.read().into_inner()) + } + + /// Reads a copy of `Self` from the suffix of `bytes`. + /// + /// `read_from_suffix` reads a `Self` from the last `size_of::()` + /// bytes of `bytes`. If `bytes.len() < size_of::()`, it returns + /// `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::FromBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketTrailer { + /// frame_check_sequence: [u8; 4], + /// } + /// + /// // These are more bytes than are needed to encode a `PacketTrailer`. + /// let bytes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_slice(); + /// + /// let trailer = PacketTrailer::read_from_suffix(bytes).unwrap(); + /// + /// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]); + /// ``` + #[inline] + fn read_from_suffix(bytes: &[u8]) -> Option + where + Self: Sized, + { + Ref::<_, Unalign>::new_unaligned_from_suffix(bytes) + .map(|(_, r)| r.read().into_inner()) + } +} + +/// Analyzes whether a type is [`AsBytes`]. +/// +/// This derive analyzes, at compile time, whether the annotated type satisfies +/// the [safety conditions] of `AsBytes` and implements `AsBytes` if it is +/// sound to do so. This derive can be applied to structs, enums, and unions; +/// e.g.: +/// +/// ``` +/// # use zerocopy_derive::{AsBytes}; +/// #[derive(AsBytes)] +/// #[repr(C)] +/// struct MyStruct { +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(AsBytes)] +/// #[repr(u8)] +/// enum MyEnum { +/// # Variant, +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(AsBytes)] +/// #[repr(C)] +/// union MyUnion { +/// # variant: u8, +/// # /* +/// ... +/// # */ +/// } +/// ``` +/// +/// [safety conditions]: trait@AsBytes#safety +/// +/// # Error Messages +/// +/// Due to the way that the custom derive for `AsBytes` is implemented, you may +/// get an error like this: +/// +/// ```text +/// error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied +/// --> lib.rs:23:10 +/// | +/// 1 | #[derive(AsBytes)] +/// | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` +/// | +/// = help: the trait `ShouldBe` is implemented for `HasPadding` +/// ``` +/// +/// This error indicates that the type being annotated has padding bytes, which +/// is illegal for `AsBytes` types. Consider reducing the alignment of some +/// fields by using types in the [`byteorder`] module, adding explicit struct +/// fields where those padding bytes would be, or using `#[repr(packed)]`. See +/// the Rust Reference's page on [type layout] for more information +/// about type layout and padding. +/// +/// [type layout]: https://doc.rust-lang.org/reference/type-layout.html +/// +/// # Analysis +/// +/// *This section describes, roughly, the analysis performed by this derive to +/// determine whether it is sound to implement `AsBytes` for a given type. +/// Unless you are modifying the implementation of this derive, or attempting to +/// manually implement `AsBytes` for a type yourself, you don't need to read +/// this section.* +/// +/// If a type has the following properties, then this derive can implement +/// `AsBytes` for that type: +/// +/// - If the type is a struct: +/// - It must have a defined representation (`repr(C)`, `repr(transparent)`, +/// or `repr(packed)`). +/// - All of its fields must be `AsBytes`. +/// - Its layout must have no padding. This is always true for +/// `repr(transparent)` and `repr(packed)`. For `repr(C)`, see the layout +/// algorithm described in the [Rust Reference]. +/// - If the type is an enum: +/// - It must be a C-like enum (meaning that all variants have no fields). +/// - It must have a defined representation (`repr`s `C`, `u8`, `u16`, `u32`, +/// `u64`, `usize`, `i8`, `i16`, `i32`, `i64`, or `isize`). +/// - The type must not contain any [`UnsafeCell`]s (this is required in order +/// for it to be sound to construct a `&[u8]` and a `&T` to the same region of +/// memory). The type may contain references or pointers to `UnsafeCell`s so +/// long as those values can themselves be initialized from zeroes (`AsBytes` +/// is not currently implemented for, e.g., `Option<&UnsafeCell<_>>`, but it +/// could be one day). +/// +/// [`UnsafeCell`]: core::cell::UnsafeCell +/// +/// This analysis is subject to change. Unsafe code may *only* rely on the +/// documented [safety conditions] of `FromBytes`, and must *not* rely on the +/// implementation details of this derive. +/// +/// [Rust Reference]: https://doc.rust-lang.org/reference/type-layout.html +#[cfg(any(feature = "derive", test))] +#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] +pub use zerocopy_derive::AsBytes; + +/// Types that can be viewed as an immutable slice of initialized bytes. +/// +/// Any `AsBytes` type can be viewed as a slice of initialized bytes of the same +/// size. This is useful for efficiently serializing structured data as raw +/// bytes. +/// +/// # Implementation +/// +/// **Do not implement this trait yourself!** Instead, use +/// [`#[derive(AsBytes)]`][derive] (requires the `derive` Cargo feature); e.g.: +/// +/// ``` +/// # use zerocopy_derive::AsBytes; +/// #[derive(AsBytes)] +/// #[repr(C)] +/// struct MyStruct { +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(AsBytes)] +/// #[repr(u8)] +/// enum MyEnum { +/// # Variant0, +/// # /* +/// ... +/// # */ +/// } +/// +/// #[derive(AsBytes)] +/// #[repr(C)] +/// union MyUnion { +/// # variant: u8, +/// # /* +/// ... +/// # */ +/// } +/// ``` +/// +/// This derive performs a sophisticated, compile-time safety analysis to +/// determine whether a type is `AsBytes`. See the [derive +/// documentation][derive] for guidance on how to interpret error messages +/// produced by the derive's analysis. +/// +/// # Safety +/// +/// *This section describes what is required in order for `T: AsBytes`, and +/// what unsafe code may assume of such types. If you don't plan on implementing +/// `AsBytes` manually, and you don't plan on writing unsafe code that +/// operates on `AsBytes` types, then you don't need to read this section.* +/// +/// If `T: AsBytes`, then unsafe code may assume that: +/// - It is sound to treat any `t: T` as an immutable `[u8]` of length +/// `size_of_val(t)`. +/// - Given `t: &T`, it is sound to construct a `b: &[u8]` where `b.len() == +/// size_of_val(t)` at the same address as `t`, and it is sound for both `b` +/// and `t` to be live at the same time. +/// +/// If a type is marked as `AsBytes` which violates this contract, it may cause +/// undefined behavior. +/// +/// `#[derive(AsBytes)]` only permits [types which satisfy these +/// requirements][derive-analysis]. +/// +#[cfg_attr( + feature = "derive", + doc = "[derive]: zerocopy_derive::AsBytes", + doc = "[derive-analysis]: zerocopy_derive::AsBytes#analysis" +)] +#[cfg_attr( + not(feature = "derive"), + doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.AsBytes.html"), + doc = concat!("[derive-analysis]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.AsBytes.html#analysis"), +)] +pub unsafe trait AsBytes { + // The `Self: Sized` bound makes it so that this function doesn't prevent + // `AsBytes` from being object safe. Note that other `AsBytes` methods + // prevent object safety, but those provide a benefit in exchange for object + // safety. If at some point we remove those methods, change their type + // signatures, or move them out of this trait so that `AsBytes` is object + // safe again, it's important that this function not prevent object safety. + #[doc(hidden)] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized; + + /// Gets the bytes of this value. + /// + /// `as_bytes` provides access to the bytes of this value as an immutable + /// byte slice. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::AsBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let header = PacketHeader { + /// src_port: [0, 1], + /// dst_port: [2, 3], + /// length: [4, 5], + /// checksum: [6, 7], + /// }; + /// + /// let bytes = header.as_bytes(); + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]); + /// ``` + #[inline(always)] + fn as_bytes(&self) -> &[u8] { + // Note that this method does not have a `Self: Sized` bound; + // `size_of_val` works for unsized values too. + let len = mem::size_of_val(self); + let slf: *const Self = self; + + // SAFETY: + // - `slf.cast::()` is valid for reads for `len * + // mem::size_of::()` many bytes because... + // - `slf` is the same pointer as `self`, and `self` is a reference + // which points to an object whose size is `len`. Thus... + // - The entire region of `len` bytes starting at `slf` is contained + // within a single allocation. + // - `slf` is non-null. + // - `slf` is trivially aligned to `align_of::() == 1`. + // - `Self: AsBytes` ensures that all of the bytes of `slf` are + // initialized. + // - Since `slf` is derived from `self`, and `self` is an immutable + // reference, the only other references to this memory region that + // could exist are other immutable references, and those don't allow + // mutation. `AsBytes` prohibits types which contain `UnsafeCell`s, + // which are the only types for which this rule wouldn't be sufficient. + // - The total size of the resulting slice is no larger than + // `isize::MAX` because no allocation produced by safe code can be + // larger than `isize::MAX`. + // + // TODO(#429): Add references to docs and quotes. + unsafe { slice::from_raw_parts(slf.cast::(), len) } + } + + /// Gets the bytes of this value mutably. + /// + /// `as_bytes_mut` provides access to the bytes of this value as a mutable + /// byte slice. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::AsBytes; + /// # use zerocopy_derive::*; + /// + /// # #[derive(Eq, PartialEq, Debug)] + /// #[derive(AsBytes, FromZeroes, FromBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let mut header = PacketHeader { + /// src_port: [0, 1], + /// dst_port: [2, 3], + /// length: [4, 5], + /// checksum: [6, 7], + /// }; + /// + /// let bytes = header.as_bytes_mut(); + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]); + /// + /// bytes.reverse(); + /// + /// assert_eq!(header, PacketHeader { + /// src_port: [7, 6], + /// dst_port: [5, 4], + /// length: [3, 2], + /// checksum: [1, 0], + /// }); + /// ``` + #[inline(always)] + fn as_bytes_mut(&mut self) -> &mut [u8] + where + Self: FromBytes, + { + // Note that this method does not have a `Self: Sized` bound; + // `size_of_val` works for unsized values too. + let len = mem::size_of_val(self); + let slf: *mut Self = self; + + // SAFETY: + // - `slf.cast::()` is valid for reads and writes for `len * + // mem::size_of::()` many bytes because... + // - `slf` is the same pointer as `self`, and `self` is a reference + // which points to an object whose size is `len`. Thus... + // - The entire region of `len` bytes starting at `slf` is contained + // within a single allocation. + // - `slf` is non-null. + // - `slf` is trivially aligned to `align_of::() == 1`. + // - `Self: AsBytes` ensures that all of the bytes of `slf` are + // initialized. + // - `Self: FromBytes` ensures that no write to this memory region + // could result in it containing an invalid `Self`. + // - Since `slf` is derived from `self`, and `self` is a mutable + // reference, no other references to this memory region can exist. + // - The total size of the resulting slice is no larger than + // `isize::MAX` because no allocation produced by safe code can be + // larger than `isize::MAX`. + // + // TODO(#429): Add references to docs and quotes. + unsafe { slice::from_raw_parts_mut(slf.cast::(), len) } + } + + /// Writes a copy of `self` to `bytes`. + /// + /// If `bytes.len() != size_of_val(self)`, `write_to` returns `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::AsBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let header = PacketHeader { + /// src_port: [0, 1], + /// dst_port: [2, 3], + /// length: [4, 5], + /// checksum: [6, 7], + /// }; + /// + /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0]; + /// + /// header.write_to(&mut bytes[..]); + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7]); + /// ``` + /// + /// If too many or too few target bytes are provided, `write_to` returns + /// `None` and leaves the target bytes unmodified: + /// + /// ``` + /// # use zerocopy::AsBytes; + /// # let header = u128::MAX; + /// let mut excessive_bytes = &mut [0u8; 128][..]; + /// + /// let write_result = header.write_to(excessive_bytes); + /// + /// assert!(write_result.is_none()); + /// assert_eq!(excessive_bytes, [0u8; 128]); + /// ``` + #[inline] + fn write_to(&self, bytes: &mut [u8]) -> Option<()> { + if bytes.len() != mem::size_of_val(self) { + return None; + } + + bytes.copy_from_slice(self.as_bytes()); + Some(()) + } + + /// Writes a copy of `self` to the prefix of `bytes`. + /// + /// `write_to_prefix` writes `self` to the first `size_of_val(self)` bytes + /// of `bytes`. If `bytes.len() < size_of_val(self)`, it returns `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::AsBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let header = PacketHeader { + /// src_port: [0, 1], + /// dst_port: [2, 3], + /// length: [4, 5], + /// checksum: [6, 7], + /// }; + /// + /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + /// + /// header.write_to_prefix(&mut bytes[..]); + /// + /// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 6, 7, 0, 0]); + /// ``` + /// + /// If insufficient target bytes are provided, `write_to_prefix` returns + /// `None` and leaves the target bytes unmodified: + /// + /// ``` + /// # use zerocopy::AsBytes; + /// # let header = u128::MAX; + /// let mut insufficent_bytes = &mut [0, 0][..]; + /// + /// let write_result = header.write_to_suffix(insufficent_bytes); + /// + /// assert!(write_result.is_none()); + /// assert_eq!(insufficent_bytes, [0, 0]); + /// ``` + #[inline] + fn write_to_prefix(&self, bytes: &mut [u8]) -> Option<()> { + let size = mem::size_of_val(self); + bytes.get_mut(..size)?.copy_from_slice(self.as_bytes()); + Some(()) + } + + /// Writes a copy of `self` to the suffix of `bytes`. + /// + /// `write_to_suffix` writes `self` to the last `size_of_val(self)` bytes of + /// `bytes`. If `bytes.len() < size_of_val(self)`, it returns `None`. + /// + /// # Examples + /// + /// ``` + /// use zerocopy::AsBytes; + /// # use zerocopy_derive::*; + /// + /// #[derive(AsBytes)] + /// #[repr(C)] + /// struct PacketHeader { + /// src_port: [u8; 2], + /// dst_port: [u8; 2], + /// length: [u8; 2], + /// checksum: [u8; 2], + /// } + /// + /// let header = PacketHeader { + /// src_port: [0, 1], + /// dst_port: [2, 3], + /// length: [4, 5], + /// checksum: [6, 7], + /// }; + /// + /// let mut bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + /// + /// header.write_to_suffix(&mut bytes[..]); + /// + /// assert_eq!(bytes, [0, 0, 0, 1, 2, 3, 4, 5, 6, 7]); + /// + /// let mut insufficent_bytes = &mut [0, 0][..]; + /// + /// let write_result = header.write_to_suffix(insufficent_bytes); + /// + /// assert!(write_result.is_none()); + /// assert_eq!(insufficent_bytes, [0, 0]); + /// ``` + /// + /// If insufficient target bytes are provided, `write_to_suffix` returns + /// `None` and leaves the target bytes unmodified: + /// + /// ``` + /// # use zerocopy::AsBytes; + /// # let header = u128::MAX; + /// let mut insufficent_bytes = &mut [0, 0][..]; + /// + /// let write_result = header.write_to_suffix(insufficent_bytes); + /// + /// assert!(write_result.is_none()); + /// assert_eq!(insufficent_bytes, [0, 0]); + /// ``` + #[inline] + fn write_to_suffix(&self, bytes: &mut [u8]) -> Option<()> { + let start = bytes.len().checked_sub(mem::size_of_val(self))?; + bytes + .get_mut(start..) + .expect("`start` should be in-bounds of `bytes`") + .copy_from_slice(self.as_bytes()); + Some(()) + } +} + +/// Types with no alignment requirement. +/// +/// WARNING: Do not implement this trait yourself! Instead, use +/// `#[derive(Unaligned)]` (requires the `derive` Cargo feature). +/// +/// If `T: Unaligned`, then `align_of::() == 1`. +/// +/// # Safety +/// +/// *This section describes what is required in order for `T: Unaligned`, and +/// what unsafe code may assume of such types. `#[derive(Unaligned)]` only +/// permits types which satisfy these requirements. If you don't plan on +/// implementing `Unaligned` manually, and you don't plan on writing unsafe code +/// that operates on `Unaligned` types, then you don't need to read this +/// section.* +/// +/// If `T: Unaligned`, then unsafe code may assume that it is sound to produce a +/// reference to `T` at any memory location regardless of alignment. If a type +/// is marked as `Unaligned` which violates this contract, it may cause +/// undefined behavior. +pub unsafe trait Unaligned { + // The `Self: Sized` bound makes it so that `Unaligned` is still object + // safe. + #[doc(hidden)] + fn only_derive_is_allowed_to_implement_this_trait() + where + Self: Sized; +} + +safety_comment! { + /// SAFETY: + /// Per the reference [1], "the unit tuple (`()`) ... is guaranteed as a + /// zero-sized type to have a size of 0 and an alignment of 1." + /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: There + /// is only one possible sequence of 0 bytes, and `()` is inhabited. + /// - `AsBytes`: Since `()` has size 0, it contains no padding bytes. + /// - `Unaligned`: `()` has alignment 1. + /// + /// [1] https://doc.rust-lang.org/reference/type-layout.html#tuple-layout + unsafe_impl!((): TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_unaligned!(()); +} + +safety_comment! { + /// SAFETY: + /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: all bit + /// patterns are valid for numeric types [1] + /// - `AsBytes`: numeric types have no padding bytes [1] + /// - `Unaligned` (`u8` and `i8` only): The reference [2] specifies the size + /// of `u8` and `i8` as 1 byte. We also know that: + /// - Alignment is >= 1 [3] + /// - Size is an integer multiple of alignment [4] + /// - The only value >= 1 for which 1 is an integer multiple is 1 + /// Therefore, the only possible alignment for `u8` and `i8` is 1. + /// + /// [1] Per https://doc.rust-lang.org/beta/reference/types/numeric.html#bit-validity: + /// + /// For every numeric type, `T`, the bit validity of `T` is equivalent to + /// the bit validity of `[u8; size_of::()]`. An uninitialized byte is + /// not a valid `u8`. + /// + /// TODO(https://github.com/rust-lang/reference/pull/1392): Once this text + /// is available on the Stable docs, cite those instead. + /// + /// [2] https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout + /// + /// [3] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment: + /// + /// Alignment is measured in bytes, and must be at least 1. + /// + /// [4] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment: + /// + /// The size of a value is always a multiple of its alignment. + /// + /// TODO(#278): Once we've updated the trait docs to refer to `u8`s rather + /// than bits or bytes, update this comment, especially the reference to + /// [1]. + unsafe_impl!(u8: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + unsafe_impl!(i8: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_unaligned!(u8, i8); + unsafe_impl!(u16: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(i16: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(u32: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(i32: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(u64: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(i64: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(u128: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(i128: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(usize: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(isize: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(f32: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(f64: TryFromBytes, FromZeroes, FromBytes, AsBytes); +} + +safety_comment! { + /// SAFETY: + /// - `FromZeroes`: Valid since "[t]he value false has the bit pattern + /// 0x00" [1]. + /// - `AsBytes`: Since "the boolean type has a size and alignment of 1 each" + /// and "The value false has the bit pattern 0x00 and the value true has + /// the bit pattern 0x01" [1]. Thus, the only byte of the bool is always + /// initialized. + /// - `Unaligned`: Per the reference [1], "[a]n object with the boolean type + /// has a size and alignment of 1 each." + /// + /// [1] https://doc.rust-lang.org/reference/types/boolean.html + unsafe_impl!(bool: FromZeroes, AsBytes, Unaligned); + assert_unaligned!(bool); + /// SAFETY: + /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid` + /// closure: + /// - Given `t: *mut bool` and `let r = *mut u8`, `r` refers to an object + /// of the same size as that referred to by `t`. This is true because + /// `bool` and `u8` have the same size (1 byte) [1]. + /// - Since the closure takes a `&u8` argument, given a `Ptr<'a, bool>` + /// which satisfies the preconditions of + /// `TryFromBytes::::is_bit_valid`, it must be guaranteed that the + /// memory referenced by that `Ptr` always contains a valid `u8`. Since + /// `bool`'s single byte is always initialized, `is_bit_valid`'s + /// precondition requires that the same is true of its argument. Since + /// `u8`'s only bit validity invariant is that its single byte must be + /// initialized, this memory is guaranteed to contain a valid `u8`. + /// - The alignment of `bool` is equal to the alignment of `u8`. [1] [2] + /// - The impl must only return `true` for its argument if the original + /// `Ptr` refers to a valid `bool`. We only return true if the + /// `u8` value is 0 or 1, and both of these are valid values for `bool`. + /// [3] + /// + /// [1] Per https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout: + /// + /// The size of most primitives is given in this table. + /// + /// | Type | `size_of::() ` | + /// |-----------|----------------------| + /// | `bool` | 1 | + /// | `u8`/`i8` | 1 | + /// + /// [2] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment: + /// + /// The size of a value is always a multiple of its alignment. + /// + /// [3] Per https://doc.rust-lang.org/reference/types/boolean.html: + /// + /// The value false has the bit pattern 0x00 and the value true has the + /// bit pattern 0x01. + unsafe_impl!(bool: TryFromBytes; |byte: &u8| *byte < 2); +} +safety_comment! { + /// SAFETY: + /// - `FromZeroes`: Per reference [1], "[a] value of type char is a Unicode + /// scalar value (i.e. a code point that is not a surrogate), represented + /// as a 32-bit unsigned word in the 0x0000 to 0xD7FF or 0xE000 to + /// 0x10FFFF range" which contains 0x0000. + /// - `AsBytes`: `char` is per reference [1] "represented as a 32-bit + /// unsigned word" (`u32`) which is `AsBytes`. Note that unlike `u32`, not + /// all bit patterns are valid for `char`. + /// + /// [1] https://doc.rust-lang.org/reference/types/textual.html + unsafe_impl!(char: FromZeroes, AsBytes); + /// SAFETY: + /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid` + /// closure: + /// - Given `t: *mut char` and `let r = *mut u32`, `r` refers to an object + /// of the same size as that referred to by `t`. This is true because + /// `char` and `u32` have the same size [1]. + /// - Since the closure takes a `&u32` argument, given a `Ptr<'a, char>` + /// which satisfies the preconditions of + /// `TryFromBytes::::is_bit_valid`, it must be guaranteed that the + /// memory referenced by that `Ptr` always contains a valid `u32`. Since + /// `char`'s bytes are always initialized [2], `is_bit_valid`'s + /// precondition requires that the same is true of its argument. Since + /// `u32`'s only bit validity invariant is that its bytes must be + /// initialized, this memory is guaranteed to contain a valid `u32`. + /// - The alignment of `char` is equal to the alignment of `u32`. [1] + /// - The impl must only return `true` for its argument if the original + /// `Ptr` refers to a valid `char`. `char::from_u32` guarantees + /// that it returns `None` if its input is not a valid `char`. [3] + /// + /// [1] Per https://doc.rust-lang.org/nightly/reference/types/textual.html#layout-and-bit-validity: + /// + /// `char` is guaranteed to have the same size and alignment as `u32` on + /// all platforms. + /// + /// [2] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32: + /// + /// Every byte of a `char` is guaranteed to be initialized. + /// + /// [3] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32: + /// + /// `from_u32()` will return `None` if the input is not a valid value for + /// a `char`. + unsafe_impl!(char: TryFromBytes; |candidate: &u32| char::from_u32(*candidate).is_some()); +} +safety_comment! { + /// SAFETY: + /// - `FromZeroes`, `AsBytes`, `Unaligned`: Per the reference [1], `str` + /// has the same layout as `[u8]`, and `[u8]` is `FromZeroes`, `AsBytes`, + /// and `Unaligned`. + /// + /// Note that we don't `assert_unaligned!(str)` because `assert_unaligned!` + /// uses `align_of`, which only works for `Sized` types. + /// + /// TODO(#429): Add quotes from documentation. + /// + /// [1] https://doc.rust-lang.org/reference/type-layout.html#str-layout + unsafe_impl!(str: FromZeroes, AsBytes, Unaligned); + /// SAFETY: + /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid` + /// closure: + /// - Given `t: *mut str` and `let r = *mut [u8]`, `r` refers to an object + /// of the same size as that referred to by `t`. This is true because + /// `str` and `[u8]` have the same representation. [1] + /// - Since the closure takes a `&[u8]` argument, given a `Ptr<'a, str>` + /// which satisfies the preconditions of + /// `TryFromBytes::::is_bit_valid`, it must be guaranteed that the + /// memory referenced by that `Ptr` always contains a valid `[u8]`. + /// Since `str`'s bytes are always initialized [1], `is_bit_valid`'s + /// precondition requires that the same is true of its argument. Since + /// `[u8]`'s only bit validity invariant is that its bytes must be + /// initialized, this memory is guaranteed to contain a valid `[u8]`. + /// - The alignment of `str` is equal to the alignment of `[u8]`. [1] + /// - The impl must only return `true` for its argument if the original + /// `Ptr` refers to a valid `str`. `str::from_utf8` guarantees that + /// it returns `Err` if its input is not a valid `str`. [2] + /// + /// [1] Per https://doc.rust-lang.org/reference/types/textual.html: + /// + /// A value of type `str` is represented the same was as `[u8]`. + /// + /// [2] Per https://doc.rust-lang.org/core/str/fn.from_utf8.html#errors: + /// + /// Returns `Err` if the slice is not UTF-8. + unsafe_impl!(str: TryFromBytes; |candidate: &[u8]| core::str::from_utf8(candidate).is_ok()); +} + +safety_comment! { + // `NonZeroXxx` is `AsBytes`, but not `FromZeroes` or `FromBytes`. + // + /// SAFETY: + /// - `AsBytes`: `NonZeroXxx` has the same layout as its associated + /// primitive. Since it is the same size, this guarantees it has no + /// padding - integers have no padding, and there's no room for padding + /// if it can represent all of the same values except 0. + /// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that + /// `Option` and `Option` both have size 1. [1] [2] + /// This is worded in a way that makes it unclear whether it's meant as a + /// guarantee, but given the purpose of those types, it's virtually + /// unthinkable that that would ever change. `Option` cannot be smaller + /// than its contained type, which implies that, and `NonZeroX8` are of + /// size 1 or 0. `NonZeroX8` can represent multiple states, so they cannot + /// be 0 bytes, which means that they must be 1 byte. The only valid + /// alignment for a 1-byte type is 1. + /// + /// TODO(#429): Add quotes from documentation. + /// + /// [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html + /// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html + /// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation + /// that layout is the same as primitive layout. + unsafe_impl!(NonZeroU8: AsBytes, Unaligned); + unsafe_impl!(NonZeroI8: AsBytes, Unaligned); + assert_unaligned!(NonZeroU8, NonZeroI8); + unsafe_impl!(NonZeroU16: AsBytes); + unsafe_impl!(NonZeroI16: AsBytes); + unsafe_impl!(NonZeroU32: AsBytes); + unsafe_impl!(NonZeroI32: AsBytes); + unsafe_impl!(NonZeroU64: AsBytes); + unsafe_impl!(NonZeroI64: AsBytes); + unsafe_impl!(NonZeroU128: AsBytes); + unsafe_impl!(NonZeroI128: AsBytes); + unsafe_impl!(NonZeroUsize: AsBytes); + unsafe_impl!(NonZeroIsize: AsBytes); + /// SAFETY: + /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid` + /// closure: + /// - Given `t: *mut NonZeroXxx` and `let r = *mut xxx`, `r` refers to an + /// object of the same size as that referred to by `t`. This is true + /// because `NonZeroXxx` and `xxx` have the same size. [1] + /// - Since the closure takes a `&xxx` argument, given a `Ptr<'a, + /// NonZeroXxx>` which satisfies the preconditions of + /// `TryFromBytes::::is_bit_valid`, it must be guaranteed + /// that the memory referenced by that `Ptr` always contains a valid + /// `xxx`. Since `NonZeroXxx`'s bytes are always initialized [1], + /// `is_bit_valid`'s precondition requires that the same is true of its + /// argument. Since `xxx`'s only bit validity invariant is that its + /// bytes must be initialized, this memory is guaranteed to contain a + /// valid `xxx`. + /// - The alignment of `NonZeroXxx` is equal to the alignment of `xxx`. + /// [1] + /// - The impl must only return `true` for its argument if the original + /// `Ptr` refers to a valid `NonZeroXxx`. The only `xxx` + /// which is not also a valid `NonZeroXxx` is 0. [1] + /// + /// [1] Per https://doc.rust-lang.org/core/num/struct.NonZeroU16.html: + /// + /// `NonZeroU16` is guaranteed to have the same layout and bit validity as + /// `u16` with the exception that `0` is not a valid instance. + unsafe_impl!(NonZeroU8: TryFromBytes; |n: &u8| *n != 0); + unsafe_impl!(NonZeroI8: TryFromBytes; |n: &i8| *n != 0); + unsafe_impl!(NonZeroU16: TryFromBytes; |n: &u16| *n != 0); + unsafe_impl!(NonZeroI16: TryFromBytes; |n: &i16| *n != 0); + unsafe_impl!(NonZeroU32: TryFromBytes; |n: &u32| *n != 0); + unsafe_impl!(NonZeroI32: TryFromBytes; |n: &i32| *n != 0); + unsafe_impl!(NonZeroU64: TryFromBytes; |n: &u64| *n != 0); + unsafe_impl!(NonZeroI64: TryFromBytes; |n: &i64| *n != 0); + unsafe_impl!(NonZeroU128: TryFromBytes; |n: &u128| *n != 0); + unsafe_impl!(NonZeroI128: TryFromBytes; |n: &i128| *n != 0); + unsafe_impl!(NonZeroUsize: TryFromBytes; |n: &usize| *n != 0); + unsafe_impl!(NonZeroIsize: TryFromBytes; |n: &isize| *n != 0); +} +safety_comment! { + /// SAFETY: + /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`, + /// `AsBytes`: The Rust compiler reuses `0` value to represent `None`, so + /// `size_of::>() == size_of::()`; see + /// `NonZeroXxx` documentation. + /// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that + /// `Option` and `Option` both have size 1. [1] [2] + /// This is worded in a way that makes it unclear whether it's meant as a + /// guarantee, but given the purpose of those types, it's virtually + /// unthinkable that that would ever change. The only valid alignment for + /// a 1-byte type is 1. + /// + /// TODO(#429): Add quotes from documentation. + /// + /// [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html + /// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html + /// + /// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation + /// for layout guarantees. + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_unaligned!(Option, Option); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); + unsafe_impl!(Option: TryFromBytes, FromZeroes, FromBytes, AsBytes); +} + +safety_comment! { + /// SAFETY: + /// The following types can be transmuted from `[0u8; size_of::()]`. [1] + /// None of them contain `UnsafeCell`s, and so they all soundly implement + /// `FromZeroes`. + /// + /// [1] Per + /// https://doc.rust-lang.org/nightly/core/option/index.html#representation: + /// + /// Rust guarantees to optimize the following types `T` such that + /// [`Option`] has the same size and alignment as `T`. In some of these + /// cases, Rust further guarantees that `transmute::<_, Option>([0u8; + /// size_of::()])` is sound and produces `Option::::None`. These + /// cases are identified by the second column: + /// + /// | `T` | `transmute::<_, Option>([0u8; size_of::()])` sound? | + /// |-----------------------|-----------------------------------------------------------| + /// | [`Box`] | when `U: Sized` | + /// | `&U` | when `U: Sized` | + /// | `&mut U` | when `U: Sized` | + /// | [`ptr::NonNull`] | when `U: Sized` | + /// | `fn`, `extern "C" fn` | always | + /// + /// TODO(#429), TODO(https://github.com/rust-lang/rust/pull/115333): Cite + /// the Stable docs once they're available. + #[cfg(feature = "alloc")] + unsafe_impl!( + #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] + T => FromZeroes for Option> + ); + unsafe_impl!(T => FromZeroes for Option<&'_ T>); + unsafe_impl!(T => FromZeroes for Option<&'_ mut T>); + unsafe_impl!(T => FromZeroes for Option>); + unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeroes for opt_fn!(...)); + unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeroes for opt_extern_c_fn!(...)); +} + +safety_comment! { + /// SAFETY: + /// Per reference [1]: + /// "For all T, the following are guaranteed: + /// size_of::>() == 0 + /// align_of::>() == 1". + /// This gives: + /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: There + /// is only one possible sequence of 0 bytes, and `PhantomData` is + /// inhabited. + /// - `AsBytes`: Since `PhantomData` has size 0, it contains no padding + /// bytes. + /// - `Unaligned`: Per the preceding reference, `PhantomData` has alignment + /// 1. + /// + /// [1] https://doc.rust-lang.org/std/marker/struct.PhantomData.html#layout-1 + unsafe_impl!(T: ?Sized => TryFromBytes for PhantomData); + unsafe_impl!(T: ?Sized => FromZeroes for PhantomData); + unsafe_impl!(T: ?Sized => FromBytes for PhantomData); + unsafe_impl!(T: ?Sized => AsBytes for PhantomData); + unsafe_impl!(T: ?Sized => Unaligned for PhantomData); + assert_unaligned!(PhantomData<()>, PhantomData, PhantomData); +} +safety_comment! { + /// SAFETY: + /// `Wrapping` is guaranteed by its docs [1] to have the same layout and + /// bit validity as `T`. Also, `Wrapping` is `#[repr(transparent)]`, and + /// has a single field, which is `pub`. Per the reference [2], this means + /// that the `#[repr(transparent)]` attribute is "considered part of the + /// public ABI". + /// + /// - `TryFromBytes`: The safety requirements for `unsafe_impl!` with an + /// `is_bit_valid` closure: + /// - Given `t: *mut Wrapping` and `let r = *mut T`, `r` refers to an + /// object of the same size as that referred to by `t`. This is true + /// because `Wrapping` and `T` have the same layout + /// - The alignment of `Wrapping` is equal to the alignment of `T`. + /// - The impl must only return `true` for its argument if the original + /// `Ptr>` refers to a valid `Wrapping`. Since + /// `Wrapping` has the same bit validity as `T`, and since our impl + /// just calls `T::is_bit_valid`, our impl returns `true` exactly when + /// its argument contains a valid `Wrapping`. + /// - `FromBytes`: Since `Wrapping` has the same bit validity as `T`, if + /// `T: FromBytes`, then all initialized byte sequences are valid + /// instances of `Wrapping`. Similarly, if `T: FromBytes`, then + /// `Wrapping` doesn't contain any `UnsafeCell`s. Thus, `impl FromBytes + /// for Wrapping where T: FromBytes` is a sound impl. + /// - `AsBytes`: Since `Wrapping` has the same bit validity as `T`, if + /// `T: AsBytes`, then all valid instances of `Wrapping` have all of + /// their bytes initialized. Similarly, if `T: AsBytes`, then + /// `Wrapping` doesn't contain any `UnsafeCell`s. Thus, `impl AsBytes + /// for Wrapping where T: AsBytes` is a valid impl. + /// - `Unaligned`: Since `Wrapping` has the same layout as `T`, + /// `Wrapping` has alignment 1 exactly when `T` does. + /// + /// [1] Per https://doc.rust-lang.org/core/num/struct.NonZeroU16.html: + /// + /// `NonZeroU16` is guaranteed to have the same layout and bit validity as + /// `u16` with the exception that `0` is not a valid instance. + /// + /// TODO(#429): Add quotes from documentation. + /// + /// [1] TODO(https://doc.rust-lang.org/nightly/core/num/struct.Wrapping.html#layout-1): + /// Reference this documentation once it's available on stable. + /// + /// [2] https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent + unsafe_impl!(T: TryFromBytes => TryFromBytes for Wrapping; |candidate: Ptr| { + // SAFETY: + // - Since `T` and `Wrapping` have the same layout and bit validity + // and contain the same fields, `T` contains `UnsafeCell`s exactly + // where `Wrapping` does. Thus, all memory and `UnsafeCell` + // preconditions of `T::is_bit_valid` hold exactly when the same + // preconditions for `Wrapping::is_bit_valid` hold. + // - By the same token, since `candidate` is guaranteed to have its + // bytes initialized where there are always initialized bytes in + // `Wrapping`, the same is true for `T`. + unsafe { T::is_bit_valid(candidate) } + }); + unsafe_impl!(T: FromZeroes => FromZeroes for Wrapping); + unsafe_impl!(T: FromBytes => FromBytes for Wrapping); + unsafe_impl!(T: AsBytes => AsBytes for Wrapping); + unsafe_impl!(T: Unaligned => Unaligned for Wrapping); + assert_unaligned!(Wrapping<()>, Wrapping); +} +safety_comment! { + // `MaybeUninit` is `FromZeroes` and `FromBytes`, but never `AsBytes` + // since it may contain uninitialized bytes. + // + /// SAFETY: + /// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: + /// `MaybeUninit` has no restrictions on its contents. Unfortunately, + /// in addition to bit validity, `TryFromBytes`, `FromZeroes` and + /// `FromBytes` also require that implementers contain no `UnsafeCell`s. + /// Thus, we require `T: Trait` in order to ensure that `T` - and thus + /// `MaybeUninit` - contains to `UnsafeCell`s. Thus, requiring that `T` + /// implement each of these traits is sufficient. + /// - `Unaligned`: "MaybeUninit is guaranteed to have the same size, + /// alignment, and ABI as T" [1] + /// + /// [1] https://doc.rust-lang.org/stable/core/mem/union.MaybeUninit.html#layout-1 + /// + /// TODO(https://github.com/google/zerocopy/issues/251): If we split + /// `FromBytes` and `RefFromBytes`, or if we introduce a separate + /// `NoCell`/`Freeze` trait, we can relax the trait bounds for `FromZeroes` + /// and `FromBytes`. + unsafe_impl!(T: TryFromBytes => TryFromBytes for MaybeUninit); + unsafe_impl!(T: FromZeroes => FromZeroes for MaybeUninit); + unsafe_impl!(T: FromBytes => FromBytes for MaybeUninit); + unsafe_impl!(T: Unaligned => Unaligned for MaybeUninit); + assert_unaligned!(MaybeUninit<()>, MaybeUninit); +} +safety_comment! { + /// SAFETY: + /// `ManuallyDrop` has the same layout and bit validity as `T` [1], and + /// accessing the inner value is safe (meaning that it's unsound to leave + /// the inner value uninitialized while exposing the `ManuallyDrop` to safe + /// code). + /// - `FromZeroes`, `FromBytes`: Since it has the same layout as `T`, any + /// valid `T` is a valid `ManuallyDrop`. If `T: FromZeroes`, a sequence + /// of zero bytes is a valid `T`, and thus a valid `ManuallyDrop`. If + /// `T: FromBytes`, any sequence of bytes is a valid `T`, and thus a valid + /// `ManuallyDrop`. + /// - `AsBytes`: Since it has the same layout as `T`, and since it's unsound + /// to let safe code access a `ManuallyDrop` whose inner value is + /// uninitialized, safe code can only ever access a `ManuallyDrop` whose + /// contents are a valid `T`. Since `T: AsBytes`, this means that safe + /// code can only ever access a `ManuallyDrop` with all initialized bytes. + /// - `Unaligned`: `ManuallyDrop` has the same layout (and thus alignment) + /// as `T`, and `T: Unaligned` guarantees that that alignment is 1. + /// + /// `ManuallyDrop` is guaranteed to have the same layout and bit + /// validity as `T` + /// + /// [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: + /// + /// TODO(#429): + /// - Add quotes from docs. + /// - Once [1] (added in + /// https://github.com/rust-lang/rust/pull/115522) is available on stable, + /// quote the stable docs instead of the nightly docs. + unsafe_impl!(T: ?Sized + FromZeroes => FromZeroes for ManuallyDrop); + unsafe_impl!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop); + unsafe_impl!(T: ?Sized + AsBytes => AsBytes for ManuallyDrop); + unsafe_impl!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop); + assert_unaligned!(ManuallyDrop<()>, ManuallyDrop); +} +safety_comment! { + /// SAFETY: + /// Per the reference [1]: + /// + /// An array of `[T; N]` has a size of `size_of::() * N` and the same + /// alignment of `T`. Arrays are laid out so that the zero-based `nth` + /// element of the array is offset from the start of the array by `n * + /// size_of::()` bytes. + /// + /// ... + /// + /// Slices have the same layout as the section of the array they slice. + /// + /// In other words, the layout of a `[T]` or `[T; N]` is a sequence of `T`s + /// laid out back-to-back with no bytes in between. Therefore, `[T]` or `[T; + /// N]` are `TryFromBytes`, `FromZeroes`, `FromBytes`, and `AsBytes` if `T` + /// is (respectively). Furthermore, since an array/slice has "the same + /// alignment of `T`", `[T]` and `[T; N]` are `Unaligned` if `T` is. + /// + /// Note that we don't `assert_unaligned!` for slice types because + /// `assert_unaligned!` uses `align_of`, which only works for `Sized` types. + /// + /// [1] https://doc.rust-lang.org/reference/type-layout.html#array-layout + unsafe_impl!(const N: usize, T: FromZeroes => FromZeroes for [T; N]); + unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]); + unsafe_impl!(const N: usize, T: AsBytes => AsBytes for [T; N]); + unsafe_impl!(const N: usize, T: Unaligned => Unaligned for [T; N]); + assert_unaligned!([(); 0], [(); 1], [u8; 0], [u8; 1]); + unsafe_impl!(T: TryFromBytes => TryFromBytes for [T]; |c: Ptr<[T]>| { + // SAFETY: Assuming the preconditions of `is_bit_valid` are satisfied, + // so too will the postcondition: that, if `is_bit_valid(candidate)` + // returns true, `*candidate` contains a valid `Self`. Per the reference + // [1]: + // + // An array of `[T; N]` has a size of `size_of::() * N` and the + // same alignment of `T`. Arrays are laid out so that the zero-based + // `nth` element of the array is offset from the start of the array by + // `n * size_of::()` bytes. + // + // ... + // + // Slices have the same layout as the section of the array they slice. + // + // In other words, the layout of a `[T] is a sequence of `T`s laid out + // back-to-back with no bytes in between. If all elements in `candidate` + // are `is_bit_valid`, so too is `candidate`. + // + // Note that any of the below calls may panic, but it would still be + // sound even if it did. `is_bit_valid` does not promise that it will + // not panic (in fact, it explicitly warns that it's a possibility), and + // we have not violated any safety invariants that we must fix before + // returning. + c.iter().all(|elem| + // SAFETY: We uphold the safety contract of `is_bit_valid(elem)`, by + // precondition on the surrounding call to `is_bit_valid`. The + // memory referenced by `elem` is contained entirely within `c`, and + // satisfies the preconditions satisfied by `c`. By axiom, we assume + // that `Iterator:all` does not invalidate these preconditions + // (e.g., by writing to `elem`.) Since `elem` is derived from `c`, + // it is only possible for uninitialized bytes to occur in `elem` at + // the same bytes they occur within `c`. + unsafe { ::is_bit_valid(elem) } + ) + }); + unsafe_impl!(T: FromZeroes => FromZeroes for [T]); + unsafe_impl!(T: FromBytes => FromBytes for [T]); + unsafe_impl!(T: AsBytes => AsBytes for [T]); + unsafe_impl!(T: Unaligned => Unaligned for [T]); +} +safety_comment! { + /// SAFETY: + /// - `FromZeroes`: For thin pointers (note that `T: Sized`), the zero + /// pointer is considered "null". [1] No operations which require + /// provenance are legal on null pointers, so this is not a footgun. + /// + /// NOTE(#170): Implementing `FromBytes` and `AsBytes` for raw pointers + /// would be sound, but carries provenance footguns. We want to support + /// `FromBytes` and `AsBytes` for raw pointers eventually, but we are + /// holding off until we can figure out how to address those footguns. + /// + /// [1] TODO(https://github.com/rust-lang/rust/pull/116988): Cite the + /// documentation once this PR lands. + unsafe_impl!(T => FromZeroes for *const T); + unsafe_impl!(T => FromZeroes for *mut T); +} + +// SIMD support +// +// Per the Unsafe Code Guidelines Reference [1]: +// +// Packed SIMD vector types are `repr(simd)` homogeneous tuple-structs +// containing `N` elements of type `T` where `N` is a power-of-two and the +// size and alignment requirements of `T` are equal: +// +// ```rust +// #[repr(simd)] +// struct Vector(T_0, ..., T_(N - 1)); +// ``` +// +// ... +// +// The size of `Vector` is `N * size_of::()` and its alignment is an +// implementation-defined function of `T` and `N` greater than or equal to +// `align_of::()`. +// +// ... +// +// Vector elements are laid out in source field order, enabling random access +// to vector elements by reinterpreting the vector as an array: +// +// ```rust +// union U { +// vec: Vector, +// arr: [T; N] +// } +// +// assert_eq!(size_of::>(), size_of::<[T; N]>()); +// assert!(align_of::>() >= align_of::<[T; N]>()); +// +// unsafe { +// let u = U { vec: Vector(t_0, ..., t_(N - 1)) }; +// +// assert_eq!(u.vec.0, u.arr[0]); +// // ... +// assert_eq!(u.vec.(N - 1), u.arr[N - 1]); +// } +// ``` +// +// Given this background, we can observe that: +// - The size and bit pattern requirements of a SIMD type are equivalent to the +// equivalent array type. Thus, for any SIMD type whose primitive `T` is +// `TryFromBytes`, `FromZeroes`, `FromBytes`, or `AsBytes`, that SIMD type is +// also `TryFromBytes`, `FromZeroes`, `FromBytes`, or `AsBytes` respectively. +// - Since no upper bound is placed on the alignment, no SIMD type can be +// guaranteed to be `Unaligned`. +// +// Also per [1]: +// +// This chapter represents the consensus from issue #38. The statements in +// here are not (yet) "guaranteed" not to change until an RFC ratifies them. +// +// See issue #38 [2]. While this behavior is not technically guaranteed, the +// likelihood that the behavior will change such that SIMD types are no longer +// `TryFromBytes`, `FromZeroes`, `FromBytes`, or `AsBytes` is next to zero, as +// that would defeat the entire purpose of SIMD types. Nonetheless, we put this +// behavior behind the `simd` Cargo feature, which requires consumers to opt +// into this stability hazard. +// +// [1] https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html +// [2] https://github.com/rust-lang/unsafe-code-guidelines/issues/38 +#[cfg(feature = "simd")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "simd")))] +mod simd { + /// Defines a module which implements `TryFromBytes`, `FromZeroes`, + /// `FromBytes`, and `AsBytes` for a set of types from a module in + /// `core::arch`. + /// + /// `$arch` is both the name of the defined module and the name of the + /// module in `core::arch`, and `$typ` is the list of items from that module + /// to implement `FromZeroes`, `FromBytes`, and `AsBytes` for. + #[allow(unused_macros)] // `allow(unused_macros)` is needed because some + // target/feature combinations don't emit any impls + // and thus don't use this macro. + macro_rules! simd_arch_mod { + (#[cfg $cfg:tt] $arch:ident, $mod:ident, $($typ:ident),*) => { + #[cfg $cfg] + #[cfg_attr(doc_cfg, doc(cfg $cfg))] + mod $mod { + use core::arch::$arch::{$($typ),*}; + + use crate::*; + impl_known_layout!($($typ),*); + safety_comment! { + /// SAFETY: + /// See comment on module definition for justification. + $( unsafe_impl!($typ: TryFromBytes, FromZeroes, FromBytes, AsBytes); )* + } + } + }; + } + + #[rustfmt::skip] + const _: () = { + simd_arch_mod!( + #[cfg(target_arch = "x86")] + x86, x86, __m128, __m128d, __m128i, __m256, __m256d, __m256i + ); + simd_arch_mod!( + #[cfg(all(feature = "simd-nightly", target_arch = "x86"))] + x86, x86_nightly, __m512bh, __m512, __m512d, __m512i + ); + simd_arch_mod!( + #[cfg(target_arch = "x86_64")] + x86_64, x86_64, __m128, __m128d, __m128i, __m256, __m256d, __m256i + ); + simd_arch_mod!( + #[cfg(all(feature = "simd-nightly", target_arch = "x86_64"))] + x86_64, x86_64_nightly, __m512bh, __m512, __m512d, __m512i + ); + simd_arch_mod!( + #[cfg(target_arch = "wasm32")] + wasm32, wasm32, v128 + ); + simd_arch_mod!( + #[cfg(all(feature = "simd-nightly", target_arch = "powerpc"))] + powerpc, powerpc, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long + ); + simd_arch_mod!( + #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))] + powerpc64, powerpc64, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long + ); + simd_arch_mod!( + #[cfg(target_arch = "aarch64")] + aarch64, aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t, + int8x8x3_t, int8x8x4_t, int8x16_t, int8x16x2_t, int8x16x3_t, int8x16x4_t, int16x4_t, + int16x8_t, int32x2_t, int32x4_t, int64x1_t, int64x2_t, poly8x8_t, poly8x8x2_t, poly8x8x3_t, + poly8x8x4_t, poly8x16_t, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t, poly16x4_t, poly16x8_t, + poly64x1_t, poly64x2_t, uint8x8_t, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t, uint8x16_t, + uint8x16x2_t, uint8x16x3_t, uint8x16x4_t, uint16x4_t, uint16x8_t, uint32x2_t, uint32x4_t, + uint64x1_t, uint64x2_t + ); + simd_arch_mod!( + #[cfg(all(feature = "simd-nightly", target_arch = "arm"))] + arm, arm, int8x4_t, uint8x4_t + ); + }; +} + +/// Safely transmutes a value of one type to a value of another type of the same +/// size. +/// +/// The expression `$e` must have a concrete type, `T`, which implements +/// `AsBytes`. The `transmute!` expression must also have a concrete type, `U` +/// (`U` is inferred from the calling context), and `U` must implement +/// `FromBytes`. +/// +/// Note that the `T` produced by the expression `$e` will *not* be dropped. +/// Semantically, its bits will be copied into a new value of type `U`, the +/// original `T` will be forgotten, and the value of type `U` will be returned. +/// +/// # Examples +/// +/// ``` +/// # use zerocopy::transmute; +/// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; +/// +/// let two_dimensional: [[u8; 4]; 2] = transmute!(one_dimensional); +/// +/// assert_eq!(two_dimensional, [[0, 1, 2, 3], [4, 5, 6, 7]]); +/// ``` +#[macro_export] +macro_rules! transmute { + ($e:expr) => {{ + // NOTE: This must be a macro (rather than a function with trait bounds) + // because there's no way, in a generic context, to enforce that two + // types have the same size. `core::mem::transmute` uses compiler magic + // to enforce this so long as the types are concrete. + + let e = $e; + if false { + // This branch, though never taken, ensures that the type of `e` is + // `AsBytes` and that the type of this macro invocation expression + // is `FromBytes`. + + struct AssertIsAsBytes(T); + let _ = AssertIsAsBytes(e); + + struct AssertIsFromBytes(U); + #[allow(unused, unreachable_code)] + let u = AssertIsFromBytes(loop {}); + u.0 + } else { + // SAFETY: `core::mem::transmute` ensures that the type of `e` and + // the type of this macro invocation expression have the same size. + // We know this transmute is safe thanks to the `AsBytes` and + // `FromBytes` bounds enforced by the `false` branch. + // + // We use this reexport of `core::mem::transmute` because we know it + // will always be available for crates which are using the 2015 + // edition of Rust. By contrast, if we were to use + // `std::mem::transmute`, this macro would not work for such crates + // in `no_std` contexts, and if we were to use + // `core::mem::transmute`, this macro would not work in `std` + // contexts in which `core` was not manually imported. This is not a + // problem for 2018 edition crates. + unsafe { + // Clippy: It's okay to transmute a type to itself. + #[allow(clippy::useless_transmute)] + $crate::macro_util::core_reexport::mem::transmute(e) + } + } + }} +} + +/// Safely transmutes a mutable or immutable reference of one type to an +/// immutable reference of another type of the same size. +/// +/// The expression `$e` must have a concrete type, `&T` or `&mut T`, where `T: +/// Sized + AsBytes`. The `transmute_ref!` expression must also have a concrete +/// type, `&U` (`U` is inferred from the calling context), where `U: Sized + +/// FromBytes`. It must be the case that `align_of::() >= align_of::()`. +/// +/// The lifetime of the input type, `&T` or `&mut T`, must be the same as or +/// outlive the lifetime of the output type, `&U`. +/// +/// # Examples +/// +/// ``` +/// # use zerocopy::transmute_ref; +/// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; +/// +/// let two_dimensional: &[[u8; 4]; 2] = transmute_ref!(&one_dimensional); +/// +/// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]); +/// ``` +/// +/// # Alignment increase error message +/// +/// Because of limitations on macros, the error message generated when +/// `transmute_ref!` is used to transmute from a type of lower alignment to a +/// type of higher alignment is somewhat confusing. For example, the following +/// code: +/// +/// ```compile_fail +/// const INCREASE_ALIGNMENT: &u16 = zerocopy::transmute_ref!(&[0u8; 2]); +/// ``` +/// +/// ...generates the following error: +/// +/// ```text +/// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types +/// --> src/lib.rs:1524:34 +/// | +/// 5 | const INCREASE_ALIGNMENT: &u16 = zerocopy::transmute_ref!(&[0u8; 2]); +/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/// | +/// = note: source type: `AlignOf<[u8; 2]>` (8 bits) +/// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits) +/// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info) +/// ``` +/// +/// This is saying that `max(align_of::(), align_of::()) != +/// align_of::()`, which is equivalent to `align_of::() < +/// align_of::()`. +#[macro_export] +macro_rules! transmute_ref { + ($e:expr) => {{ + // NOTE: This must be a macro (rather than a function with trait bounds) + // because there's no way, in a generic context, to enforce that two + // types have the same size or alignment. + + // Ensure that the source type is a reference or a mutable reference + // (note that mutable references are implicitly reborrowed here). + let e: &_ = $e; + + #[allow(unused, clippy::diverging_sub_expression)] + if false { + // This branch, though never taken, ensures that the type of `e` is + // `&T` where `T: 't + Sized + AsBytes`, that the type of this macro + // expression is `&U` where `U: 'u + Sized + FromBytes`, and that + // `'t` outlives `'u`. + + struct AssertIsAsBytes<'a, T: ::core::marker::Sized + $crate::AsBytes>(&'a T); + let _ = AssertIsAsBytes(e); + + struct AssertIsFromBytes<'a, U: ::core::marker::Sized + $crate::FromBytes>(&'a U); + #[allow(unused, unreachable_code)] + let u = AssertIsFromBytes(loop {}); + u.0 + } else if false { + // This branch, though never taken, ensures that `size_of::() == + // size_of::()` and that that `align_of::() >= + // align_of::()`. + + // `t` is inferred to have type `T` because it's assigned to `e` (of + // type `&T`) as `&t`. + let mut t = unreachable!(); + e = &t; + + // `u` is inferred to have type `U` because it's used as `&u` as the + // value returned from this branch. + let u; + + $crate::assert_size_eq!(t, u); + $crate::assert_align_gt_eq!(t, u); + + &u + } else { + // SAFETY: For source type `Src` and destination type `Dst`: + // - We know that `Src: AsBytes` and `Dst: FromBytes` thanks to the + // uses of `AssertIsAsBytes` and `AssertIsFromBytes` above. + // - We know that `size_of::() == size_of::()` thanks to + // the use of `assert_size_eq!` above. + // - We know that `align_of::() >= align_of::()` thanks to + // the use of `assert_align_gt_eq!` above. + unsafe { $crate::macro_util::transmute_ref(e) } + } + }} +} + +/// Safely transmutes a mutable reference of one type to an mutable reference of +/// another type of the same size. +/// +/// The expression `$e` must have a concrete type, `&mut T`, where `T: Sized + +/// AsBytes`. The `transmute_mut!` expression must also have a concrete type, +/// `&mut U` (`U` is inferred from the calling context), where `U: Sized + +/// FromBytes`. It must be the case that `align_of::() >= align_of::()`. +/// +/// The lifetime of the input type, `&mut T`, must be the same as or outlive the +/// lifetime of the output type, `&mut U`. +/// +/// # Examples +/// +/// ``` +/// # use zerocopy::transmute_mut; +/// let mut one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; +/// +/// let two_dimensional: &mut [[u8; 4]; 2] = transmute_mut!(&mut one_dimensional); +/// +/// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]); +/// +/// two_dimensional.reverse(); +/// +/// assert_eq!(one_dimensional, [4, 5, 6, 7, 0, 1, 2, 3]); +/// ``` +/// +/// # Alignment increase error message +/// +/// Because of limitations on macros, the error message generated when +/// `transmute_mut!` is used to transmute from a type of lower alignment to a +/// type of higher alignment is somewhat confusing. For example, the following +/// code: +/// +/// ```compile_fail +/// const INCREASE_ALIGNMENT: &mut u16 = zerocopy::transmute_mut!(&mut [0u8; 2]); +/// ``` +/// +/// ...generates the following error: +/// +/// ```text +/// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types +/// --> src/lib.rs:1524:34 +/// | +/// 5 | const INCREASE_ALIGNMENT: &mut u16 = zerocopy::transmute_mut!(&mut [0u8; 2]); +/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/// | +/// = note: source type: `AlignOf<[u8; 2]>` (8 bits) +/// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits) +/// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) +/// ``` +/// +/// This is saying that `max(align_of::(), align_of::()) != +/// align_of::()`, which is equivalent to `align_of::() < +/// align_of::()`. +#[macro_export] +macro_rules! transmute_mut { + ($e:expr) => {{ + // NOTE: This must be a macro (rather than a function with trait bounds) + // because there's no way, in a generic context, to enforce that two + // types have the same size or alignment. + + // Ensure that the source type is a mutable reference. + let e: &mut _ = $e; + + #[allow(unused, clippy::diverging_sub_expression)] + if false { + // This branch, though never taken, ensures that the type of `e` is + // `&mut T` where `T: 't + Sized + FromBytes + AsBytes`, that the + // type of this macro expression is `&mut U` where `U: 'u + Sized + + // FromBytes + AsBytes`. + + // We use immutable references here rather than mutable so that, if + // this macro is used in a const context (in which, as of this + // writing, mutable references are banned), the error message + // appears to originate in the user's code rather than in the + // internals of this macro. + struct AssertSrcIsFromBytes<'a, T: ::core::marker::Sized + $crate::FromBytes>(&'a T); + struct AssertSrcIsAsBytes<'a, T: ::core::marker::Sized + $crate::AsBytes>(&'a T); + struct AssertDstIsFromBytes<'a, T: ::core::marker::Sized + $crate::FromBytes>(&'a T); + struct AssertDstIsAsBytes<'a, T: ::core::marker::Sized + $crate::AsBytes>(&'a T); + + if true { + let _ = AssertSrcIsFromBytes(&*e); + } else { + let _ = AssertSrcIsAsBytes(&*e); + } + + if true { + #[allow(unused, unreachable_code)] + let u = AssertDstIsFromBytes(loop {}); + &mut *u.0 + } else { + #[allow(unused, unreachable_code)] + let u = AssertDstIsAsBytes(loop {}); + &mut *u.0 + } + } else if false { + // This branch, though never taken, ensures that `size_of::() == + // size_of::()` and that that `align_of::() >= + // align_of::()`. + + // `t` is inferred to have type `T` because it's assigned to `e` (of + // type `&mut T`) as `&mut t`. + let mut t = unreachable!(); + e = &mut t; + + // `u` is inferred to have type `U` because it's used as `&mut u` as + // the value returned from this branch. + let u; + + $crate::assert_size_eq!(t, u); + $crate::assert_align_gt_eq!(t, u); + + &mut u + } else { + // SAFETY: For source type `Src` and destination type `Dst`: + // - We know that `Src: FromBytes + AsBytes` and `Dst: FromBytes + + // AsBytes` thanks to the uses of `AssertSrcIsFromBytes`, + // `AssertSrcIsAsBytes`, `AssertDstIsFromBytes`, and + // `AssertDstIsAsBytes` above. + // - We know that `size_of::() == size_of::()` thanks to + // the use of `assert_size_eq!` above. + // - We know that `align_of::() >= align_of::()` thanks to + // the use of `assert_align_gt_eq!` above. + unsafe { $crate::macro_util::transmute_mut(e) } + } + }} +} + +/// Includes a file and safely transmutes it to a value of an arbitrary type. +/// +/// The file will be included as a byte array, `[u8; N]`, which will be +/// transmuted to another type, `T`. `T` is inferred from the calling context, +/// and must implement [`FromBytes`]. +/// +/// The file is located relative to the current file (similarly to how modules +/// are found). The provided path is interpreted in a platform-specific way at +/// compile time. So, for instance, an invocation with a Windows path containing +/// backslashes `\` would not compile correctly on Unix. +/// +/// `include_value!` is ignorant of byte order. For byte order-aware types, see +/// the [`byteorder`] module. +/// +/// # Examples +/// +/// Assume there are two files in the same directory with the following +/// contents: +/// +/// File `data` (no trailing newline): +/// +/// ```text +/// abcd +/// ``` +/// +/// File `main.rs`: +/// +/// ```rust +/// use zerocopy::include_value; +/// # macro_rules! include_value { +/// # ($file:expr) => { zerocopy::include_value!(concat!("../testdata/include_value/", $file)) }; +/// # } +/// +/// fn main() { +/// let as_u32: u32 = include_value!("data"); +/// assert_eq!(as_u32, u32::from_ne_bytes([b'a', b'b', b'c', b'd'])); +/// let as_i32: i32 = include_value!("data"); +/// assert_eq!(as_i32, i32::from_ne_bytes([b'a', b'b', b'c', b'd'])); +/// } +/// ``` +#[doc(alias("include_bytes", "include_data", "include_type"))] +#[macro_export] +macro_rules! include_value { + ($file:expr $(,)?) => { + $crate::transmute!(*::core::include_bytes!($file)) + }; +} + +/// A typed reference derived from a byte slice. +/// +/// A `Ref` is a reference to a `T` which is stored in a byte slice, `B`. +/// Unlike a native reference (`&T` or `&mut T`), `Ref` has the same +/// mutability as the byte slice it was constructed from (`B`). +/// +/// # Examples +/// +/// `Ref` can be used to treat a sequence of bytes as a structured type, and to +/// read and write the fields of that type as if the byte slice reference were +/// simply a reference to that type. +/// +/// ```rust +/// # #[cfg(feature = "derive")] { // This example uses derives, and won't compile without them +/// use zerocopy::{AsBytes, ByteSlice, ByteSliceMut, FromBytes, FromZeroes, Ref, Unaligned}; +/// +/// #[derive(FromZeroes, FromBytes, AsBytes, Unaligned)] +/// #[repr(C)] +/// struct UdpHeader { +/// src_port: [u8; 2], +/// dst_port: [u8; 2], +/// length: [u8; 2], +/// checksum: [u8; 2], +/// } +/// +/// struct UdpPacket { +/// header: Ref, +/// body: B, +/// } +/// +/// impl UdpPacket { +/// pub fn parse(bytes: B) -> Option> { +/// let (header, body) = Ref::new_unaligned_from_prefix(bytes)?; +/// Some(UdpPacket { header, body }) +/// } +/// +/// pub fn get_src_port(&self) -> [u8; 2] { +/// self.header.src_port +/// } +/// } +/// +/// impl UdpPacket { +/// pub fn set_src_port(&mut self, src_port: [u8; 2]) { +/// self.header.src_port = src_port; +/// } +/// } +/// # } +/// ``` +pub struct Ref(B, PhantomData); + +/// Deprecated: prefer [`Ref`] instead. +#[deprecated(since = "0.7.0", note = "LayoutVerified has been renamed to Ref")] +#[doc(hidden)] +pub type LayoutVerified = Ref; + +impl Ref +where + B: ByteSlice, +{ + /// Constructs a new `Ref`. + /// + /// `new` verifies that `bytes.len() == size_of::()` and that `bytes` is + /// aligned to `align_of::()`, and constructs a new `Ref`. If either of + /// these checks fail, it returns `None`. + #[inline] + pub fn new(bytes: B) -> Option> { + if bytes.len() != mem::size_of::() || !util::aligned_to::<_, T>(bytes.deref()) { + return None; + } + Some(Ref(bytes, PhantomData)) + } + + /// Constructs a new `Ref` from the prefix of a byte slice. + /// + /// `new_from_prefix` verifies that `bytes.len() >= size_of::()` and that + /// `bytes` is aligned to `align_of::()`. It consumes the first + /// `size_of::()` bytes from `bytes` to construct a `Ref`, and returns + /// the remaining bytes to the caller. If either the length or alignment + /// checks fail, it returns `None`. + #[inline] + pub fn new_from_prefix(bytes: B) -> Option<(Ref, B)> { + if bytes.len() < mem::size_of::() || !util::aligned_to::<_, T>(bytes.deref()) { + return None; + } + let (bytes, suffix) = bytes.split_at(mem::size_of::()); + Some((Ref(bytes, PhantomData), suffix)) + } + + /// Constructs a new `Ref` from the suffix of a byte slice. + /// + /// `new_from_suffix` verifies that `bytes.len() >= size_of::()` and that + /// the last `size_of::()` bytes of `bytes` are aligned to + /// `align_of::()`. It consumes the last `size_of::()` bytes from + /// `bytes` to construct a `Ref`, and returns the preceding bytes to the + /// caller. If either the length or alignment checks fail, it returns + /// `None`. + #[inline] + pub fn new_from_suffix(bytes: B) -> Option<(B, Ref)> { + let bytes_len = bytes.len(); + let split_at = bytes_len.checked_sub(mem::size_of::())?; + let (prefix, bytes) = bytes.split_at(split_at); + if !util::aligned_to::<_, T>(bytes.deref()) { + return None; + } + Some((prefix, Ref(bytes, PhantomData))) + } +} + +impl Ref +where + B: ByteSlice, +{ + /// Constructs a new `Ref` of a slice type. + /// + /// `new_slice` verifies that `bytes.len()` is a multiple of + /// `size_of::()` and that `bytes` is aligned to `align_of::()`, and + /// constructs a new `Ref`. If either of these checks fail, it returns + /// `None`. + /// + /// # Panics + /// + /// `new_slice` panics if `T` is a zero-sized type. + #[inline] + pub fn new_slice(bytes: B) -> Option> { + let remainder = bytes + .len() + .checked_rem(mem::size_of::()) + .expect("Ref::new_slice called on a zero-sized type"); + if remainder != 0 || !util::aligned_to::<_, T>(bytes.deref()) { + return None; + } + Some(Ref(bytes, PhantomData)) + } + + /// Constructs a new `Ref` of a slice type from the prefix of a byte slice. + /// + /// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::() * + /// count` and that `bytes` is aligned to `align_of::()`. It consumes the + /// first `size_of::() * count` bytes from `bytes` to construct a `Ref`, + /// and returns the remaining bytes to the caller. It also ensures that + /// `sizeof::() * count` does not overflow a `usize`. If any of the + /// length, alignment, or overflow checks fail, it returns `None`. + /// + /// # Panics + /// + /// `new_slice_from_prefix` panics if `T` is a zero-sized type. + #[inline] + pub fn new_slice_from_prefix(bytes: B, count: usize) -> Option<(Ref, B)> { + let expected_len = match mem::size_of::().checked_mul(count) { + Some(len) => len, + None => return None, + }; + if bytes.len() < expected_len { + return None; + } + let (prefix, bytes) = bytes.split_at(expected_len); + Self::new_slice(prefix).map(move |l| (l, bytes)) + } + + /// Constructs a new `Ref` of a slice type from the suffix of a byte slice. + /// + /// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::() * + /// count` and that `bytes` is aligned to `align_of::()`. It consumes the + /// last `size_of::() * count` bytes from `bytes` to construct a `Ref`, + /// and returns the preceding bytes to the caller. It also ensures that + /// `sizeof::() * count` does not overflow a `usize`. If any of the + /// length, alignment, or overflow checks fail, it returns `None`. + /// + /// # Panics + /// + /// `new_slice_from_suffix` panics if `T` is a zero-sized type. + #[inline] + pub fn new_slice_from_suffix(bytes: B, count: usize) -> Option<(B, Ref)> { + let expected_len = match mem::size_of::().checked_mul(count) { + Some(len) => len, + None => return None, + }; + let split_at = bytes.len().checked_sub(expected_len)?; + let (bytes, suffix) = bytes.split_at(split_at); + Self::new_slice(suffix).map(move |l| (bytes, l)) + } +} + +fn map_zeroed(opt: Option>) -> Option> { + match opt { + Some(mut r) => { + r.0.fill(0); + Some(r) + } + None => None, + } +} + +fn map_prefix_tuple_zeroed( + opt: Option<(Ref, B)>, +) -> Option<(Ref, B)> { + match opt { + Some((mut r, rest)) => { + r.0.fill(0); + Some((r, rest)) + } + None => None, + } +} + +fn map_suffix_tuple_zeroed( + opt: Option<(B, Ref)>, +) -> Option<(B, Ref)> { + map_prefix_tuple_zeroed(opt.map(|(a, b)| (b, a))).map(|(a, b)| (b, a)) +} + +impl Ref +where + B: ByteSliceMut, +{ + /// Constructs a new `Ref` after zeroing the bytes. + /// + /// `new_zeroed` verifies that `bytes.len() == size_of::()` and that + /// `bytes` is aligned to `align_of::()`, and constructs a new `Ref`. If + /// either of these checks fail, it returns `None`. + /// + /// If the checks succeed, then `bytes` will be initialized to zero. This + /// can be useful when re-using buffers to ensure that sensitive data + /// previously stored in the buffer is not leaked. + #[inline(always)] + pub fn new_zeroed(bytes: B) -> Option> { + map_zeroed(Self::new(bytes)) + } + + /// Constructs a new `Ref` from the prefix of a byte slice, zeroing the + /// prefix. + /// + /// `new_from_prefix_zeroed` verifies that `bytes.len() >= size_of::()` + /// and that `bytes` is aligned to `align_of::()`. It consumes the first + /// `size_of::()` bytes from `bytes` to construct a `Ref`, and returns + /// the remaining bytes to the caller. If either the length or alignment + /// checks fail, it returns `None`. + /// + /// If the checks succeed, then the prefix which is consumed will be + /// initialized to zero. This can be useful when re-using buffers to ensure + /// that sensitive data previously stored in the buffer is not leaked. + #[inline(always)] + pub fn new_from_prefix_zeroed(bytes: B) -> Option<(Ref, B)> { + map_prefix_tuple_zeroed(Self::new_from_prefix(bytes)) + } + + /// Constructs a new `Ref` from the suffix of a byte slice, zeroing the + /// suffix. + /// + /// `new_from_suffix_zeroed` verifies that `bytes.len() >= size_of::()` + /// and that the last `size_of::()` bytes of `bytes` are aligned to + /// `align_of::()`. It consumes the last `size_of::()` bytes from + /// `bytes` to construct a `Ref`, and returns the preceding bytes to the + /// caller. If either the length or alignment checks fail, it returns + /// `None`. + /// + /// If the checks succeed, then the suffix which is consumed will be + /// initialized to zero. This can be useful when re-using buffers to ensure + /// that sensitive data previously stored in the buffer is not leaked. + #[inline(always)] + pub fn new_from_suffix_zeroed(bytes: B) -> Option<(B, Ref)> { + map_suffix_tuple_zeroed(Self::new_from_suffix(bytes)) + } +} + +impl Ref +where + B: ByteSliceMut, +{ + /// Constructs a new `Ref` of a slice type after zeroing the bytes. + /// + /// `new_slice_zeroed` verifies that `bytes.len()` is a multiple of + /// `size_of::()` and that `bytes` is aligned to `align_of::()`, and + /// constructs a new `Ref`. If either of these checks fail, it returns + /// `None`. + /// + /// If the checks succeed, then `bytes` will be initialized to zero. This + /// can be useful when re-using buffers to ensure that sensitive data + /// previously stored in the buffer is not leaked. + /// + /// # Panics + /// + /// `new_slice` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_zeroed(bytes: B) -> Option> { + map_zeroed(Self::new_slice(bytes)) + } + + /// Constructs a new `Ref` of a slice type from the prefix of a byte slice, + /// after zeroing the bytes. + /// + /// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::() * + /// count` and that `bytes` is aligned to `align_of::()`. It consumes the + /// first `size_of::() * count` bytes from `bytes` to construct a `Ref`, + /// and returns the remaining bytes to the caller. It also ensures that + /// `sizeof::() * count` does not overflow a `usize`. If any of the + /// length, alignment, or overflow checks fail, it returns `None`. + /// + /// If the checks succeed, then the suffix which is consumed will be + /// initialized to zero. This can be useful when re-using buffers to ensure + /// that sensitive data previously stored in the buffer is not leaked. + /// + /// # Panics + /// + /// `new_slice_from_prefix_zeroed` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_from_prefix_zeroed(bytes: B, count: usize) -> Option<(Ref, B)> { + map_prefix_tuple_zeroed(Self::new_slice_from_prefix(bytes, count)) + } + + /// Constructs a new `Ref` of a slice type from the prefix of a byte slice, + /// after zeroing the bytes. + /// + /// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::() * + /// count` and that `bytes` is aligned to `align_of::()`. It consumes the + /// last `size_of::() * count` bytes from `bytes` to construct a `Ref`, + /// and returns the preceding bytes to the caller. It also ensures that + /// `sizeof::() * count` does not overflow a `usize`. If any of the + /// length, alignment, or overflow checks fail, it returns `None`. + /// + /// If the checks succeed, then the consumed suffix will be initialized to + /// zero. This can be useful when re-using buffers to ensure that sensitive + /// data previously stored in the buffer is not leaked. + /// + /// # Panics + /// + /// `new_slice_from_suffix_zeroed` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_from_suffix_zeroed(bytes: B, count: usize) -> Option<(B, Ref)> { + map_suffix_tuple_zeroed(Self::new_slice_from_suffix(bytes, count)) + } +} + +impl Ref +where + B: ByteSlice, + T: Unaligned, +{ + /// Constructs a new `Ref` for a type with no alignment requirement. + /// + /// `new_unaligned` verifies that `bytes.len() == size_of::()` and + /// constructs a new `Ref`. If the check fails, it returns `None`. + #[inline(always)] + pub fn new_unaligned(bytes: B) -> Option> { + Ref::new(bytes) + } + + /// Constructs a new `Ref` from the prefix of a byte slice for a type with + /// no alignment requirement. + /// + /// `new_unaligned_from_prefix` verifies that `bytes.len() >= + /// size_of::()`. It consumes the first `size_of::()` bytes from + /// `bytes` to construct a `Ref`, and returns the remaining bytes to the + /// caller. If the length check fails, it returns `None`. + #[inline(always)] + pub fn new_unaligned_from_prefix(bytes: B) -> Option<(Ref, B)> { + Ref::new_from_prefix(bytes) + } + + /// Constructs a new `Ref` from the suffix of a byte slice for a type with + /// no alignment requirement. + /// + /// `new_unaligned_from_suffix` verifies that `bytes.len() >= + /// size_of::()`. It consumes the last `size_of::()` bytes from + /// `bytes` to construct a `Ref`, and returns the preceding bytes to the + /// caller. If the length check fails, it returns `None`. + #[inline(always)] + pub fn new_unaligned_from_suffix(bytes: B) -> Option<(B, Ref)> { + Ref::new_from_suffix(bytes) + } +} + +impl Ref +where + B: ByteSlice, + T: Unaligned, +{ + /// Constructs a new `Ref` of a slice type with no alignment requirement. + /// + /// `new_slice_unaligned` verifies that `bytes.len()` is a multiple of + /// `size_of::()` and constructs a new `Ref`. If the check fails, it + /// returns `None`. + /// + /// # Panics + /// + /// `new_slice` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_unaligned(bytes: B) -> Option> { + Ref::new_slice(bytes) + } + + /// Constructs a new `Ref` of a slice type with no alignment requirement + /// from the prefix of a byte slice. + /// + /// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::() * + /// count`. It consumes the first `size_of::() * count` bytes from + /// `bytes` to construct a `Ref`, and returns the remaining bytes to the + /// caller. It also ensures that `sizeof::() * count` does not overflow a + /// `usize`. If either the length, or overflow checks fail, it returns + /// `None`. + /// + /// # Panics + /// + /// `new_slice_unaligned_from_prefix` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_unaligned_from_prefix(bytes: B, count: usize) -> Option<(Ref, B)> { + Ref::new_slice_from_prefix(bytes, count) + } + + /// Constructs a new `Ref` of a slice type with no alignment requirement + /// from the suffix of a byte slice. + /// + /// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::() * + /// count`. It consumes the last `size_of::() * count` bytes from `bytes` + /// to construct a `Ref`, and returns the remaining bytes to the caller. It + /// also ensures that `sizeof::() * count` does not overflow a `usize`. + /// If either the length, or overflow checks fail, it returns `None`. + /// + /// # Panics + /// + /// `new_slice_unaligned_from_suffix` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_unaligned_from_suffix(bytes: B, count: usize) -> Option<(B, Ref)> { + Ref::new_slice_from_suffix(bytes, count) + } +} + +impl Ref +where + B: ByteSliceMut, + T: Unaligned, +{ + /// Constructs a new `Ref` for a type with no alignment requirement, zeroing + /// the bytes. + /// + /// `new_unaligned_zeroed` verifies that `bytes.len() == size_of::()` and + /// constructs a new `Ref`. If the check fails, it returns `None`. + /// + /// If the check succeeds, then `bytes` will be initialized to zero. This + /// can be useful when re-using buffers to ensure that sensitive data + /// previously stored in the buffer is not leaked. + #[inline(always)] + pub fn new_unaligned_zeroed(bytes: B) -> Option> { + map_zeroed(Self::new_unaligned(bytes)) + } + + /// Constructs a new `Ref` from the prefix of a byte slice for a type with + /// no alignment requirement, zeroing the prefix. + /// + /// `new_unaligned_from_prefix_zeroed` verifies that `bytes.len() >= + /// size_of::()`. It consumes the first `size_of::()` bytes from + /// `bytes` to construct a `Ref`, and returns the remaining bytes to the + /// caller. If the length check fails, it returns `None`. + /// + /// If the check succeeds, then the prefix which is consumed will be + /// initialized to zero. This can be useful when re-using buffers to ensure + /// that sensitive data previously stored in the buffer is not leaked. + #[inline(always)] + pub fn new_unaligned_from_prefix_zeroed(bytes: B) -> Option<(Ref, B)> { + map_prefix_tuple_zeroed(Self::new_unaligned_from_prefix(bytes)) + } + + /// Constructs a new `Ref` from the suffix of a byte slice for a type with + /// no alignment requirement, zeroing the suffix. + /// + /// `new_unaligned_from_suffix_zeroed` verifies that `bytes.len() >= + /// size_of::()`. It consumes the last `size_of::()` bytes from + /// `bytes` to construct a `Ref`, and returns the preceding bytes to the + /// caller. If the length check fails, it returns `None`. + /// + /// If the check succeeds, then the suffix which is consumed will be + /// initialized to zero. This can be useful when re-using buffers to ensure + /// that sensitive data previously stored in the buffer is not leaked. + #[inline(always)] + pub fn new_unaligned_from_suffix_zeroed(bytes: B) -> Option<(B, Ref)> { + map_suffix_tuple_zeroed(Self::new_unaligned_from_suffix(bytes)) + } +} + +impl Ref +where + B: ByteSliceMut, + T: Unaligned, +{ + /// Constructs a new `Ref` for a slice type with no alignment requirement, + /// zeroing the bytes. + /// + /// `new_slice_unaligned_zeroed` verifies that `bytes.len()` is a multiple + /// of `size_of::()` and constructs a new `Ref`. If the check fails, it + /// returns `None`. + /// + /// If the check succeeds, then `bytes` will be initialized to zero. This + /// can be useful when re-using buffers to ensure that sensitive data + /// previously stored in the buffer is not leaked. + /// + /// # Panics + /// + /// `new_slice` panics if `T` is a zero-sized type. + #[inline(always)] + pub fn new_slice_unaligned_zeroed(bytes: B) -> Option> { + map_zeroed(Self::new_slice_unaligned(bytes)) + } + + /// Constructs a new `Ref` of a slice type with no alignment requirement + /// from the prefix of a byte slice, after zeroing the bytes. + /// + /// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::() * + /// count`. It consumes the first `size_of::() * count` bytes from + /// `bytes` to construct a `Ref`, and returns the remaining bytes to the + /// caller. It also ensures that `sizeof::() * count` does not overflow a + /// `usize`. If either the length, or overflow checks fail, it returns + /// `None`. + /// + /// If the checks succeed, then the prefix will be initialized to zero. This + /// can be useful when re-using buffers to ensure that sensitive data + /// previously stored in the buffer is not leaked. + /// + /// # Panics + /// + /// `new_slice_unaligned_from_prefix_zeroed` panics if `T` is a zero-sized + /// type. + #[inline(always)] + pub fn new_slice_unaligned_from_prefix_zeroed( + bytes: B, + count: usize, + ) -> Option<(Ref, B)> { + map_prefix_tuple_zeroed(Self::new_slice_unaligned_from_prefix(bytes, count)) + } + + /// Constructs a new `Ref` of a slice type with no alignment requirement + /// from the suffix of a byte slice, after zeroing the bytes. + /// + /// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::() * + /// count`. It consumes the last `size_of::() * count` bytes from `bytes` + /// to construct a `Ref`, and returns the remaining bytes to the caller. It + /// also ensures that `sizeof::() * count` does not overflow a `usize`. + /// If either the length, or overflow checks fail, it returns `None`. + /// + /// If the checks succeed, then the suffix will be initialized to zero. This + /// can be useful when re-using buffers to ensure that sensitive data + /// previously stored in the buffer is not leaked. + /// + /// # Panics + /// + /// `new_slice_unaligned_from_suffix_zeroed` panics if `T` is a zero-sized + /// type. + #[inline(always)] + pub fn new_slice_unaligned_from_suffix_zeroed( + bytes: B, + count: usize, + ) -> Option<(B, Ref)> { + map_suffix_tuple_zeroed(Self::new_slice_unaligned_from_suffix(bytes, count)) + } +} + +impl<'a, B, T> Ref +where + B: 'a + ByteSlice, + T: FromBytes, +{ + /// Converts this `Ref` into a reference. + /// + /// `into_ref` consumes the `Ref`, and returns a reference to `T`. + #[inline(always)] + pub fn into_ref(self) -> &'a T { + assert!(B::INTO_REF_INTO_MUT_ARE_SOUND); + + // SAFETY: According to the safety preconditions on + // `ByteSlice::INTO_REF_INTO_MUT_ARE_SOUND`, the preceding assert + // ensures that, given `B: 'a`, it is sound to drop `self` and still + // access the underlying memory using reads for `'a`. + unsafe { self.deref_helper() } + } +} + +impl<'a, B, T> Ref +where + B: 'a + ByteSliceMut, + T: FromBytes + AsBytes, +{ + /// Converts this `Ref` into a mutable reference. + /// + /// `into_mut` consumes the `Ref`, and returns a mutable reference to `T`. + #[inline(always)] + pub fn into_mut(mut self) -> &'a mut T { + assert!(B::INTO_REF_INTO_MUT_ARE_SOUND); + + // SAFETY: According to the safety preconditions on + // `ByteSlice::INTO_REF_INTO_MUT_ARE_SOUND`, the preceding assert + // ensures that, given `B: 'a + ByteSliceMut`, it is sound to drop + // `self` and still access the underlying memory using both reads and + // writes for `'a`. + unsafe { self.deref_mut_helper() } + } +} + +impl<'a, B, T> Ref +where + B: 'a + ByteSlice, + T: FromBytes, +{ + /// Converts this `Ref` into a slice reference. + /// + /// `into_slice` consumes the `Ref`, and returns a reference to `[T]`. + #[inline(always)] + pub fn into_slice(self) -> &'a [T] { + assert!(B::INTO_REF_INTO_MUT_ARE_SOUND); + + // SAFETY: According to the safety preconditions on + // `ByteSlice::INTO_REF_INTO_MUT_ARE_SOUND`, the preceding assert + // ensures that, given `B: 'a`, it is sound to drop `self` and still + // access the underlying memory using reads for `'a`. + unsafe { self.deref_slice_helper() } + } +} + +impl<'a, B, T> Ref +where + B: 'a + ByteSliceMut, + T: FromBytes + AsBytes, +{ + /// Converts this `Ref` into a mutable slice reference. + /// + /// `into_mut_slice` consumes the `Ref`, and returns a mutable reference to + /// `[T]`. + #[inline(always)] + pub fn into_mut_slice(mut self) -> &'a mut [T] { + assert!(B::INTO_REF_INTO_MUT_ARE_SOUND); + + // SAFETY: According to the safety preconditions on + // `ByteSlice::INTO_REF_INTO_MUT_ARE_SOUND`, the preceding assert + // ensures that, given `B: 'a + ByteSliceMut`, it is sound to drop + // `self` and still access the underlying memory using both reads and + // writes for `'a`. + unsafe { self.deref_mut_slice_helper() } + } +} + +impl Ref +where + B: ByteSlice, + T: FromBytes, +{ + /// Creates an immutable reference to `T` with a specific lifetime. + /// + /// # Safety + /// + /// The type bounds on this method guarantee that it is safe to create an + /// immutable reference to `T` from `self`. However, since the lifetime `'a` + /// is not required to be shorter than the lifetime of the reference to + /// `self`, the caller must guarantee that the lifetime `'a` is valid for + /// this reference. In particular, the referent must exist for all of `'a`, + /// and no mutable references to the same memory may be constructed during + /// `'a`. + unsafe fn deref_helper<'a>(&self) -> &'a T { + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + unsafe { + &*self.0.as_ptr().cast::() + } + } +} + +impl Ref +where + B: ByteSliceMut, + T: FromBytes + AsBytes, +{ + /// Creates a mutable reference to `T` with a specific lifetime. + /// + /// # Safety + /// + /// The type bounds on this method guarantee that it is safe to create a + /// mutable reference to `T` from `self`. However, since the lifetime `'a` + /// is not required to be shorter than the lifetime of the reference to + /// `self`, the caller must guarantee that the lifetime `'a` is valid for + /// this reference. In particular, the referent must exist for all of `'a`, + /// and no other references - mutable or immutable - to the same memory may + /// be constructed during `'a`. + unsafe fn deref_mut_helper<'a>(&mut self) -> &'a mut T { + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + unsafe { + &mut *self.0.as_mut_ptr().cast::() + } + } +} + +impl Ref +where + B: ByteSlice, + T: FromBytes, +{ + /// Creates an immutable reference to `[T]` with a specific lifetime. + /// + /// # Safety + /// + /// `deref_slice_helper` has the same safety requirements as `deref_helper`. + unsafe fn deref_slice_helper<'a>(&self) -> &'a [T] { + let len = self.0.len(); + let elem_size = mem::size_of::(); + debug_assert_ne!(elem_size, 0); + // `Ref<_, [T]>` maintains the invariant that `size_of::() > 0`. + // Thus, neither the mod nor division operations here can panic. + #[allow(clippy::arithmetic_side_effects)] + let elems = { + debug_assert_eq!(len % elem_size, 0); + len / elem_size + }; + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + unsafe { + slice::from_raw_parts(self.0.as_ptr().cast::(), elems) + } + } +} + +impl Ref +where + B: ByteSliceMut, + T: FromBytes + AsBytes, +{ + /// Creates a mutable reference to `[T]` with a specific lifetime. + /// + /// # Safety + /// + /// `deref_mut_slice_helper` has the same safety requirements as + /// `deref_mut_helper`. + unsafe fn deref_mut_slice_helper<'a>(&mut self) -> &'a mut [T] { + let len = self.0.len(); + let elem_size = mem::size_of::(); + debug_assert_ne!(elem_size, 0); + // `Ref<_, [T]>` maintains the invariant that `size_of::() > 0`. + // Thus, neither the mod nor division operations here can panic. + #[allow(clippy::arithmetic_side_effects)] + let elems = { + debug_assert_eq!(len % elem_size, 0); + len / elem_size + }; + // TODO(#429): Add a "SAFETY" comment and remove this `allow`. + #[allow(clippy::undocumented_unsafe_blocks)] + unsafe { + slice::from_raw_parts_mut(self.0.as_mut_ptr().cast::(), elems) + } + } +} + +impl Ref +where + B: ByteSlice, + T: ?Sized, +{ + /// Gets the underlying bytes. + #[inline] + pub fn bytes(&self) -> &[u8] { + &self.0 + } +} + +impl Ref +where + B: ByteSliceMut, + T: ?Sized, +{ + /// Gets the underlying bytes mutably. + #[inline] + pub fn bytes_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +impl Ref +where + B: ByteSlice, + T: FromBytes, +{ + /// Reads a copy of `T`. + #[inline] + pub fn read(&self) -> T { + // SAFETY: Because of the invariants on `Ref`, we know that `self.0` is + // at least `size_of::()` bytes long, and that it is at least as + // aligned as `align_of::()`. Because `T: FromBytes`, it is sound to + // interpret these bytes as a `T`. + unsafe { ptr::read(self.0.as_ptr().cast::()) } + } +} + +impl Ref +where + B: ByteSliceMut, + T: AsBytes, +{ + /// Writes the bytes of `t` and then forgets `t`. + #[inline] + pub fn write(&mut self, t: T) { + // SAFETY: Because of the invariants on `Ref`, we know that `self.0` is + // at least `size_of::()` bytes long, and that it is at least as + // aligned as `align_of::()`. Writing `t` to the buffer will allow + // all of the bytes of `t` to be accessed as a `[u8]`, but because `T: + // AsBytes`, we know this is sound. + unsafe { ptr::write(self.0.as_mut_ptr().cast::(), t) } + } +} + +impl Deref for Ref +where + B: ByteSlice, + T: FromBytes, +{ + type Target = T; + #[inline] + fn deref(&self) -> &T { + // SAFETY: This is sound because the lifetime of `self` is the same as + // the lifetime of the return value, meaning that a) the returned + // reference cannot outlive `self` and, b) no mutable methods on `self` + // can be called during the lifetime of the returned reference. See the + // documentation on `deref_helper` for what invariants we are required + // to uphold. + unsafe { self.deref_helper() } + } +} + +impl DerefMut for Ref +where + B: ByteSliceMut, + T: FromBytes + AsBytes, +{ + #[inline] + fn deref_mut(&mut self) -> &mut T { + // SAFETY: This is sound because the lifetime of `self` is the same as + // the lifetime of the return value, meaning that a) the returned + // reference cannot outlive `self` and, b) no other methods on `self` + // can be called during the lifetime of the returned reference. See the + // documentation on `deref_mut_helper` for what invariants we are + // required to uphold. + unsafe { self.deref_mut_helper() } + } +} + +impl Deref for Ref +where + B: ByteSlice, + T: FromBytes, +{ + type Target = [T]; + #[inline] + fn deref(&self) -> &[T] { + // SAFETY: This is sound because the lifetime of `self` is the same as + // the lifetime of the return value, meaning that a) the returned + // reference cannot outlive `self` and, b) no mutable methods on `self` + // can be called during the lifetime of the returned reference. See the + // documentation on `deref_slice_helper` for what invariants we are + // required to uphold. + unsafe { self.deref_slice_helper() } + } +} + +impl DerefMut for Ref +where + B: ByteSliceMut, + T: FromBytes + AsBytes, +{ + #[inline] + fn deref_mut(&mut self) -> &mut [T] { + // SAFETY: This is sound because the lifetime of `self` is the same as + // the lifetime of the return value, meaning that a) the returned + // reference cannot outlive `self` and, b) no other methods on `self` + // can be called during the lifetime of the returned reference. See the + // documentation on `deref_mut_slice_helper` for what invariants we are + // required to uphold. + unsafe { self.deref_mut_slice_helper() } + } +} + +impl Display for Ref +where + B: ByteSlice, + T: FromBytes + Display, +{ + #[inline] + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + let inner: &T = self; + inner.fmt(fmt) + } +} + +impl Display for Ref +where + B: ByteSlice, + T: FromBytes, + [T]: Display, +{ + #[inline] + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + let inner: &[T] = self; + inner.fmt(fmt) + } +} + +impl Debug for Ref +where + B: ByteSlice, + T: FromBytes + Debug, +{ + #[inline] + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + let inner: &T = self; + fmt.debug_tuple("Ref").field(&inner).finish() + } +} + +impl Debug for Ref +where + B: ByteSlice, + T: FromBytes + Debug, +{ + #[inline] + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + let inner: &[T] = self; + fmt.debug_tuple("Ref").field(&inner).finish() + } +} + +impl Eq for Ref +where + B: ByteSlice, + T: FromBytes + Eq, +{ +} + +impl Eq for Ref +where + B: ByteSlice, + T: FromBytes + Eq, +{ +} + +impl PartialEq for Ref +where + B: ByteSlice, + T: FromBytes + PartialEq, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + self.deref().eq(other.deref()) + } +} + +impl PartialEq for Ref +where + B: ByteSlice, + T: FromBytes + PartialEq, +{ + #[inline] + fn eq(&self, other: &Self) -> bool { + self.deref().eq(other.deref()) + } +} + +impl Ord for Ref +where + B: ByteSlice, + T: FromBytes + Ord, +{ + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + let inner: &T = self; + let other_inner: &T = other; + inner.cmp(other_inner) + } +} + +impl Ord for Ref +where + B: ByteSlice, + T: FromBytes + Ord, +{ + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + let inner: &[T] = self; + let other_inner: &[T] = other; + inner.cmp(other_inner) + } +} + +impl PartialOrd for Ref +where + B: ByteSlice, + T: FromBytes + PartialOrd, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + let inner: &T = self; + let other_inner: &T = other; + inner.partial_cmp(other_inner) + } +} + +impl PartialOrd for Ref +where + B: ByteSlice, + T: FromBytes + PartialOrd, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + let inner: &[T] = self; + let other_inner: &[T] = other; + inner.partial_cmp(other_inner) + } +} + +mod sealed { + pub trait ByteSliceSealed {} +} + +// ByteSlice and ByteSliceMut abstract over [u8] references (&[u8], &mut [u8], +// Ref<[u8]>, RefMut<[u8]>, etc). We rely on various behaviors of these +// references such as that a given reference will never changes its length +// between calls to deref() or deref_mut(), and that split_at() works as +// expected. If ByteSlice or ByteSliceMut were not sealed, consumers could +// implement them in a way that violated these behaviors, and would break our +// unsafe code. Thus, we seal them and implement it only for known-good +// reference types. For the same reason, they're unsafe traits. + +#[allow(clippy::missing_safety_doc)] // TODO(fxbug.dev/99068) +/// A mutable or immutable reference to a byte slice. +/// +/// `ByteSlice` abstracts over the mutability of a byte slice reference, and is +/// implemented for various special reference types such as `Ref<[u8]>` and +/// `RefMut<[u8]>`. +/// +/// Note that, while it would be technically possible, `ByteSlice` is not +/// implemented for [`Vec`], as the only way to implement the [`split_at`] +/// method would involve reallocation, and `split_at` must be a very cheap +/// operation in order for the utilities in this crate to perform as designed. +/// +/// [`split_at`]: crate::ByteSlice::split_at +// It may seem overkill to go to this length to ensure that this doc link never +// breaks. We do this because it simplifies CI - it means that generating docs +// always succeeds, so we don't need special logic to only generate docs under +// certain features. +#[cfg_attr(feature = "alloc", doc = "[`Vec`]: alloc::vec::Vec")] +#[cfg_attr( + not(feature = "alloc"), + doc = "[`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html" +)] +pub unsafe trait ByteSlice: + Deref + Sized + self::sealed::ByteSliceSealed +{ + /// Are the [`Ref::into_ref`] and [`Ref::into_mut`] methods sound when used + /// with `Self`? If not, evaluating this constant must panic at compile + /// time. + /// + /// This exists to work around #716 on versions of zerocopy prior to 0.8. + /// + /// # Safety + /// + /// This may only be set to true if the following holds: Given the + /// following: + /// - `Self: 'a` + /// - `bytes: Self` + /// - `let ptr = bytes.as_ptr()` + /// + /// ...then: + /// - Using `ptr` to read the memory previously addressed by `bytes` is + /// sound for `'a` even after `bytes` has been dropped. + /// - If `Self: ByteSliceMut`, using `ptr` to write the memory previously + /// addressed by `bytes` is sound for `'a` even after `bytes` has been + /// dropped. + #[doc(hidden)] + const INTO_REF_INTO_MUT_ARE_SOUND: bool; + + /// Gets a raw pointer to the first byte in the slice. + #[inline] + fn as_ptr(&self) -> *const u8 { + <[u8]>::as_ptr(self) + } + + /// Splits the slice at the midpoint. + /// + /// `x.split_at(mid)` returns `x[..mid]` and `x[mid..]`. + /// + /// # Panics + /// + /// `x.split_at(mid)` panics if `mid > x.len()`. + fn split_at(self, mid: usize) -> (Self, Self); +} + +#[allow(clippy::missing_safety_doc)] // TODO(fxbug.dev/99068) +/// A mutable reference to a byte slice. +/// +/// `ByteSliceMut` abstracts over various ways of storing a mutable reference to +/// a byte slice, and is implemented for various special reference types such as +/// `RefMut<[u8]>`. +pub unsafe trait ByteSliceMut: ByteSlice + DerefMut { + /// Gets a mutable raw pointer to the first byte in the slice. + #[inline] + fn as_mut_ptr(&mut self) -> *mut u8 { + <[u8]>::as_mut_ptr(self) + } +} + +impl<'a> sealed::ByteSliceSealed for &'a [u8] {} +// TODO(#429): Add a "SAFETY" comment and remove this `allow`. +#[allow(clippy::undocumented_unsafe_blocks)] +unsafe impl<'a> ByteSlice for &'a [u8] { + // SAFETY: If `&'b [u8]: 'a`, then the underlying memory is treated as + // borrowed immutably for `'a` even if the slice itself is dropped. + const INTO_REF_INTO_MUT_ARE_SOUND: bool = true; + + #[inline] + fn split_at(self, mid: usize) -> (Self, Self) { + <[u8]>::split_at(self, mid) + } +} + +impl<'a> sealed::ByteSliceSealed for &'a mut [u8] {} +// TODO(#429): Add a "SAFETY" comment and remove this `allow`. +#[allow(clippy::undocumented_unsafe_blocks)] +unsafe impl<'a> ByteSlice for &'a mut [u8] { + // SAFETY: If `&'b mut [u8]: 'a`, then the underlying memory is treated as + // borrowed mutably for `'a` even if the slice itself is dropped. + const INTO_REF_INTO_MUT_ARE_SOUND: bool = true; + + #[inline] + fn split_at(self, mid: usize) -> (Self, Self) { + <[u8]>::split_at_mut(self, mid) + } +} + +impl<'a> sealed::ByteSliceSealed for cell::Ref<'a, [u8]> {} +// TODO(#429): Add a "SAFETY" comment and remove this `allow`. +#[allow(clippy::undocumented_unsafe_blocks)] +unsafe impl<'a> ByteSlice for cell::Ref<'a, [u8]> { + const INTO_REF_INTO_MUT_ARE_SOUND: bool = if !cfg!(doc) { + panic!("Ref::into_ref and Ref::into_mut are unsound when used with core::cell::Ref; see https://github.com/google/zerocopy/issues/716") + } else { + // When compiling documentation, allow the evaluation of this constant + // to succeed. This doesn't represent a soundness hole - it just delays + // any error to runtime. The reason we need this is that, otherwise, + // `rustdoc` will fail when trying to document this item. + false + }; + + #[inline] + fn split_at(self, mid: usize) -> (Self, Self) { + cell::Ref::map_split(self, |slice| <[u8]>::split_at(slice, mid)) + } +} + +impl<'a> sealed::ByteSliceSealed for RefMut<'a, [u8]> {} +// TODO(#429): Add a "SAFETY" comment and remove this `allow`. +#[allow(clippy::undocumented_unsafe_blocks)] +unsafe impl<'a> ByteSlice for RefMut<'a, [u8]> { + const INTO_REF_INTO_MUT_ARE_SOUND: bool = if !cfg!(doc) { + panic!("Ref::into_ref and Ref::into_mut are unsound when used with core::cell::RefMut; see https://github.com/google/zerocopy/issues/716") + } else { + // When compiling documentation, allow the evaluation of this constant + // to succeed. This doesn't represent a soundness hole - it just delays + // any error to runtime. The reason we need this is that, otherwise, + // `rustdoc` will fail when trying to document this item. + false + }; + + #[inline] + fn split_at(self, mid: usize) -> (Self, Self) { + RefMut::map_split(self, |slice| <[u8]>::split_at_mut(slice, mid)) + } +} + +// TODO(#429): Add a "SAFETY" comment and remove this `allow`. +#[allow(clippy::undocumented_unsafe_blocks)] +unsafe impl<'a> ByteSliceMut for &'a mut [u8] {} + +// TODO(#429): Add a "SAFETY" comment and remove this `allow`. +#[allow(clippy::undocumented_unsafe_blocks)] +unsafe impl<'a> ByteSliceMut for RefMut<'a, [u8]> {} + +#[cfg(feature = "alloc")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] +mod alloc_support { + use alloc::vec::Vec; + + use super::*; + + /// Extends a `Vec` by pushing `additional` new items onto the end of the + /// vector. The new items are initialized with zeroes. + /// + /// # Panics + /// + /// Panics if `Vec::reserve(additional)` fails to reserve enough memory. + #[inline(always)] + pub fn extend_vec_zeroed(v: &mut Vec, additional: usize) { + insert_vec_zeroed(v, v.len(), additional); + } + + /// Inserts `additional` new items into `Vec` at `position`. + /// The new items are initialized with zeroes. + /// + /// # Panics + /// + /// * Panics if `position > v.len()`. + /// * Panics if `Vec::reserve(additional)` fails to reserve enough memory. + #[inline] + pub fn insert_vec_zeroed(v: &mut Vec, position: usize, additional: usize) { + assert!(position <= v.len()); + v.reserve(additional); + // SAFETY: The `reserve` call guarantees that these cannot overflow: + // * `ptr.add(position)` + // * `position + additional` + // * `v.len() + additional` + // + // `v.len() - position` cannot overflow because we asserted that + // `position <= v.len()`. + unsafe { + // This is a potentially overlapping copy. + let ptr = v.as_mut_ptr(); + #[allow(clippy::arithmetic_side_effects)] + ptr.add(position).copy_to(ptr.add(position + additional), v.len() - position); + ptr.add(position).write_bytes(0, additional); + #[allow(clippy::arithmetic_side_effects)] + v.set_len(v.len() + additional); + } + } + + #[cfg(test)] + mod tests { + use core::convert::TryFrom as _; + + use super::*; + + #[test] + fn test_extend_vec_zeroed() { + // Test extending when there is an existing allocation. + let mut v = vec![100u64, 200, 300]; + extend_vec_zeroed(&mut v, 3); + assert_eq!(v.len(), 6); + assert_eq!(&*v, &[100, 200, 300, 0, 0, 0]); + drop(v); + + // Test extending when there is no existing allocation. + let mut v: Vec = Vec::new(); + extend_vec_zeroed(&mut v, 3); + assert_eq!(v.len(), 3); + assert_eq!(&*v, &[0, 0, 0]); + drop(v); + } + + #[test] + fn test_extend_vec_zeroed_zst() { + // Test extending when there is an existing (fake) allocation. + let mut v = vec![(), (), ()]; + extend_vec_zeroed(&mut v, 3); + assert_eq!(v.len(), 6); + assert_eq!(&*v, &[(), (), (), (), (), ()]); + drop(v); + + // Test extending when there is no existing (fake) allocation. + let mut v: Vec<()> = Vec::new(); + extend_vec_zeroed(&mut v, 3); + assert_eq!(&*v, &[(), (), ()]); + drop(v); + } + + #[test] + fn test_insert_vec_zeroed() { + // Insert at start (no existing allocation). + let mut v: Vec = Vec::new(); + insert_vec_zeroed(&mut v, 0, 2); + assert_eq!(v.len(), 2); + assert_eq!(&*v, &[0, 0]); + drop(v); + + // Insert at start. + let mut v = vec![100u64, 200, 300]; + insert_vec_zeroed(&mut v, 0, 2); + assert_eq!(v.len(), 5); + assert_eq!(&*v, &[0, 0, 100, 200, 300]); + drop(v); + + // Insert at middle. + let mut v = vec![100u64, 200, 300]; + insert_vec_zeroed(&mut v, 1, 1); + assert_eq!(v.len(), 4); + assert_eq!(&*v, &[100, 0, 200, 300]); + drop(v); + + // Insert at end. + let mut v = vec![100u64, 200, 300]; + insert_vec_zeroed(&mut v, 3, 1); + assert_eq!(v.len(), 4); + assert_eq!(&*v, &[100, 200, 300, 0]); + drop(v); + } + + #[test] + fn test_insert_vec_zeroed_zst() { + // Insert at start (no existing fake allocation). + let mut v: Vec<()> = Vec::new(); + insert_vec_zeroed(&mut v, 0, 2); + assert_eq!(v.len(), 2); + assert_eq!(&*v, &[(), ()]); + drop(v); + + // Insert at start. + let mut v = vec![(), (), ()]; + insert_vec_zeroed(&mut v, 0, 2); + assert_eq!(v.len(), 5); + assert_eq!(&*v, &[(), (), (), (), ()]); + drop(v); + + // Insert at middle. + let mut v = vec![(), (), ()]; + insert_vec_zeroed(&mut v, 1, 1); + assert_eq!(v.len(), 4); + assert_eq!(&*v, &[(), (), (), ()]); + drop(v); + + // Insert at end. + let mut v = vec![(), (), ()]; + insert_vec_zeroed(&mut v, 3, 1); + assert_eq!(v.len(), 4); + assert_eq!(&*v, &[(), (), (), ()]); + drop(v); + } + + #[test] + fn test_new_box_zeroed() { + assert_eq!(*u64::new_box_zeroed(), 0); + } + + #[test] + fn test_new_box_zeroed_array() { + drop(<[u32; 0x1000]>::new_box_zeroed()); + } + + #[test] + fn test_new_box_zeroed_zst() { + // This test exists in order to exercise unsafe code, especially + // when running under Miri. + #[allow(clippy::unit_cmp)] + { + assert_eq!(*<()>::new_box_zeroed(), ()); + } + } + + #[test] + fn test_new_box_slice_zeroed() { + let mut s: Box<[u64]> = u64::new_box_slice_zeroed(3); + assert_eq!(s.len(), 3); + assert_eq!(&*s, &[0, 0, 0]); + s[1] = 3; + assert_eq!(&*s, &[0, 3, 0]); + } + + #[test] + fn test_new_box_slice_zeroed_empty() { + let s: Box<[u64]> = u64::new_box_slice_zeroed(0); + assert_eq!(s.len(), 0); + } + + #[test] + fn test_new_box_slice_zeroed_zst() { + let mut s: Box<[()]> = <()>::new_box_slice_zeroed(3); + assert_eq!(s.len(), 3); + assert!(s.get(10).is_none()); + // This test exists in order to exercise unsafe code, especially + // when running under Miri. + #[allow(clippy::unit_cmp)] + { + assert_eq!(s[1], ()); + } + s[2] = (); + } + + #[test] + fn test_new_box_slice_zeroed_zst_empty() { + let s: Box<[()]> = <()>::new_box_slice_zeroed(0); + assert_eq!(s.len(), 0); + } + + #[test] + #[should_panic(expected = "mem::size_of::() * len overflows `usize`")] + fn test_new_box_slice_zeroed_panics_mul_overflow() { + let _ = u16::new_box_slice_zeroed(usize::MAX); + } + + #[test] + #[should_panic(expected = "assertion failed: size <= max_alloc")] + fn test_new_box_slice_zeroed_panics_isize_overflow() { + let max = usize::try_from(isize::MAX).unwrap(); + let _ = u16::new_box_slice_zeroed((max / mem::size_of::()) + 1); + } + } +} + +#[cfg(feature = "alloc")] +#[doc(inline)] +pub use alloc_support::*; + +#[cfg(test)] +mod tests { + #![allow(clippy::unreadable_literal)] + + use core::{cell::UnsafeCell, convert::TryInto as _, ops::Deref}; + + use static_assertions::assert_impl_all; + + use super::*; + use crate::util::testutil::*; + + // An unsized type. + // + // This is used to test the custom derives of our traits. The `[u8]` type + // gets a hand-rolled impl, so it doesn't exercise our custom derives. + #[derive(Debug, Eq, PartialEq, FromZeroes, FromBytes, AsBytes, Unaligned)] + #[repr(transparent)] + struct Unsized([u8]); + + impl Unsized { + fn from_mut_slice(slc: &mut [u8]) -> &mut Unsized { + // SAFETY: This *probably* sound - since the layouts of `[u8]` and + // `Unsized` are the same, so are the layouts of `&mut [u8]` and + // `&mut Unsized`. [1] Even if it turns out that this isn't actually + // guaranteed by the language spec, we can just change this since + // it's in test code. + // + // [1] https://github.com/rust-lang/unsafe-code-guidelines/issues/375 + unsafe { mem::transmute(slc) } + } + } + + /// Tests of when a sized `DstLayout` is extended with a sized field. + #[allow(clippy::decimal_literal_representation)] + #[test] + fn test_dst_layout_extend_sized_with_sized() { + // This macro constructs a layout corresponding to a `u8` and extends it + // with a zero-sized trailing field of given alignment `n`. The macro + // tests that the resulting layout has both size and alignment `min(n, + // P)` for all valid values of `repr(packed(P))`. + macro_rules! test_align_is_size { + ($n:expr) => { + let base = DstLayout::for_type::(); + let trailing_field = DstLayout::for_type::>(); + + let packs = + core::iter::once(None).chain((0..29).map(|p| NonZeroUsize::new(2usize.pow(p)))); + + for pack in packs { + let composite = base.extend(trailing_field, pack); + let max_align = pack.unwrap_or(DstLayout::CURRENT_MAX_ALIGN); + let align = $n.min(max_align.get()); + assert_eq!( + composite, + DstLayout { + align: NonZeroUsize::new(align).unwrap(), + size_info: SizeInfo::Sized { _size: align } + } + ) + } + }; + } + + test_align_is_size!(1); + test_align_is_size!(2); + test_align_is_size!(4); + test_align_is_size!(8); + test_align_is_size!(16); + test_align_is_size!(32); + test_align_is_size!(64); + test_align_is_size!(128); + test_align_is_size!(256); + test_align_is_size!(512); + test_align_is_size!(1024); + test_align_is_size!(2048); + test_align_is_size!(4096); + test_align_is_size!(8192); + test_align_is_size!(16384); + test_align_is_size!(32768); + test_align_is_size!(65536); + test_align_is_size!(131072); + test_align_is_size!(262144); + test_align_is_size!(524288); + test_align_is_size!(1048576); + test_align_is_size!(2097152); + test_align_is_size!(4194304); + test_align_is_size!(8388608); + test_align_is_size!(16777216); + test_align_is_size!(33554432); + test_align_is_size!(67108864); + test_align_is_size!(33554432); + test_align_is_size!(134217728); + test_align_is_size!(268435456); + } + + /// Tests of when a sized `DstLayout` is extended with a DST field. + #[test] + fn test_dst_layout_extend_sized_with_dst() { + // Test that for all combinations of real-world alignments and + // `repr_packed` values, that the extension of a sized `DstLayout`` with + // a DST field correctly computes the trailing offset in the composite + // layout. + + let aligns = (0..29).map(|p| NonZeroUsize::new(2usize.pow(p)).unwrap()); + let packs = core::iter::once(None).chain(aligns.clone().map(Some)); + + for align in aligns { + for pack in packs.clone() { + let base = DstLayout::for_type::(); + let elem_size = 42; + let trailing_field_offset = 11; + + let trailing_field = DstLayout { + align, + size_info: SizeInfo::SliceDst(TrailingSliceLayout { + _elem_size: elem_size, + _offset: 11, + }), + }; + + let composite = base.extend(trailing_field, pack); + + let max_align = pack.unwrap_or(DstLayout::CURRENT_MAX_ALIGN).get(); + + let align = align.get().min(max_align); + + assert_eq!( + composite, + DstLayout { + align: NonZeroUsize::new(align).unwrap(), + size_info: SizeInfo::SliceDst(TrailingSliceLayout { + _elem_size: elem_size, + _offset: align + trailing_field_offset, + }), + } + ) + } + } + } + + /// Tests that calling `pad_to_align` on a sized `DstLayout` adds the + /// expected amount of trailing padding. + #[test] + fn test_dst_layout_pad_to_align_with_sized() { + // For all valid alignments `align`, construct a one-byte layout aligned + // to `align`, call `pad_to_align`, and assert that the size of the + // resulting layout is equal to `align`. + for align in (0..29).map(|p| NonZeroUsize::new(2usize.pow(p)).unwrap()) { + let layout = DstLayout { align, size_info: SizeInfo::Sized { _size: 1 } }; + + assert_eq!( + layout.pad_to_align(), + DstLayout { align, size_info: SizeInfo::Sized { _size: align.get() } } + ); + } + + // Test explicitly-provided combinations of unpadded and padded + // counterparts. + + macro_rules! test { + (unpadded { size: $unpadded_size:expr, align: $unpadded_align:expr } + => padded { size: $padded_size:expr, align: $padded_align:expr }) => { + let unpadded = DstLayout { + align: NonZeroUsize::new($unpadded_align).unwrap(), + size_info: SizeInfo::Sized { _size: $unpadded_size }, + }; + let padded = unpadded.pad_to_align(); + + assert_eq!( + padded, + DstLayout { + align: NonZeroUsize::new($padded_align).unwrap(), + size_info: SizeInfo::Sized { _size: $padded_size }, + } + ); + }; + } + + test!(unpadded { size: 0, align: 4 } => padded { size: 0, align: 4 }); + test!(unpadded { size: 1, align: 4 } => padded { size: 4, align: 4 }); + test!(unpadded { size: 2, align: 4 } => padded { size: 4, align: 4 }); + test!(unpadded { size: 3, align: 4 } => padded { size: 4, align: 4 }); + test!(unpadded { size: 4, align: 4 } => padded { size: 4, align: 4 }); + test!(unpadded { size: 5, align: 4 } => padded { size: 8, align: 4 }); + test!(unpadded { size: 6, align: 4 } => padded { size: 8, align: 4 }); + test!(unpadded { size: 7, align: 4 } => padded { size: 8, align: 4 }); + test!(unpadded { size: 8, align: 4 } => padded { size: 8, align: 4 }); + + let current_max_align = DstLayout::CURRENT_MAX_ALIGN.get(); + + test!(unpadded { size: 1, align: current_max_align } + => padded { size: current_max_align, align: current_max_align }); + + test!(unpadded { size: current_max_align + 1, align: current_max_align } + => padded { size: current_max_align * 2, align: current_max_align }); + } + + /// Tests that calling `pad_to_align` on a DST `DstLayout` is a no-op. + #[test] + fn test_dst_layout_pad_to_align_with_dst() { + for align in (0..29).map(|p| NonZeroUsize::new(2usize.pow(p)).unwrap()) { + for offset in 0..10 { + for elem_size in 0..10 { + let layout = DstLayout { + align, + size_info: SizeInfo::SliceDst(TrailingSliceLayout { + _offset: offset, + _elem_size: elem_size, + }), + }; + assert_eq!(layout.pad_to_align(), layout); + } + } + } + } + + // This test takes a long time when running under Miri, so we skip it in + // that case. This is acceptable because this is a logic test that doesn't + // attempt to expose UB. + #[test] + #[cfg_attr(miri, ignore)] + fn testvalidate_cast_and_convert_metadata() { + impl From for SizeInfo { + fn from(_size: usize) -> SizeInfo { + SizeInfo::Sized { _size } + } + } + + impl From<(usize, usize)> for SizeInfo { + fn from((_offset, _elem_size): (usize, usize)) -> SizeInfo { + SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size }) + } + } + + fn layout>(s: S, align: usize) -> DstLayout { + DstLayout { size_info: s.into(), align: NonZeroUsize::new(align).unwrap() } + } + + /// This macro accepts arguments in the form of: + /// + /// layout(_, _, _).validate(_, _, _), Ok(Some((_, _))) + /// | | | | | | | | + /// base_size ----+ | | | | | | | + /// align -----------+ | | | | | | + /// trailing_size ------+ | | | | | + /// addr ---------------------------+ | | | | + /// bytes_len -------------------------+ | | | + /// cast_type ----------------------------+ | | + /// elems ---------------------------------------------+ | + /// split_at ---------------------------------------------+ + /// + /// `.validate` is shorthand for `.validate_cast_and_convert_metadata` + /// for brevity. + /// + /// Each argument can either be an iterator or a wildcard. Each + /// wildcarded variable is implicitly replaced by an iterator over a + /// representative sample of values for that variable. Each `test!` + /// invocation iterates over every combination of values provided by + /// each variable's iterator (ie, the cartesian product) and validates + /// that the results are expected. + /// + /// The final argument uses the same syntax, but it has a different + /// meaning: + /// - If it is `Ok(pat)`, then the pattern `pat` is supplied to + /// `assert_matches!` to validate the computed result for each + /// combination of input values. + /// - If it is `Err(msg)`, then `test!` validates that the call to + /// `validate_cast_and_convert_metadata` panics with the given panic + /// message. + /// + /// Note that the meta-variables that match these variables have the + /// `tt` type, and some valid expressions are not valid `tt`s (such as + /// `a..b`). In this case, wrap the expression in parentheses, and it + /// will become valid `tt`. + macro_rules! test { + ($(:$sizes:expr =>)? + layout($size:tt, $align:tt) + .validate($addr:tt, $bytes_len:tt, $cast_type:tt), $expect:pat $(,)? + ) => { + itertools::iproduct!( + test!(@generate_size $size), + test!(@generate_align $align), + test!(@generate_usize $addr), + test!(@generate_usize $bytes_len), + test!(@generate_cast_type $cast_type) + ).for_each(|(size_info, align, addr, bytes_len, cast_type)| { + // Temporarily disable the panic hook installed by the test + // harness. If we don't do this, all panic messages will be + // kept in an internal log. On its own, this isn't a + // problem, but if a non-caught panic ever happens (ie, in + // code later in this test not in this macro), all of the + // previously-buffered messages will be dumped, hiding the + // real culprit. + let previous_hook = std::panic::take_hook(); + // I don't understand why, but this seems to be required in + // addition to the previous line. + std::panic::set_hook(Box::new(|_| {})); + let actual = std::panic::catch_unwind(|| { + layout(size_info, align).validate_cast_and_convert_metadata(addr, bytes_len, cast_type) + }).map_err(|d| { + *d.downcast::<&'static str>().expect("expected string panic message").as_ref() + }); + std::panic::set_hook(previous_hook); + + assert_matches::assert_matches!( + actual, $expect, + "layout({size_info:?}, {align}).validate_cast_and_convert_metadata({addr}, {bytes_len}, {cast_type:?})", + ); + }); + }; + (@generate_usize _) => { 0..8 }; + // Generate sizes for both Sized and !Sized types. + (@generate_size _) => { + test!(@generate_size (_)).chain(test!(@generate_size (_, _))) + }; + // Generate sizes for both Sized and !Sized types by chaining + // specified iterators for each. + (@generate_size ($sized_sizes:tt | $unsized_sizes:tt)) => { + test!(@generate_size ($sized_sizes)).chain(test!(@generate_size $unsized_sizes)) + }; + // Generate sizes for Sized types. + (@generate_size (_)) => { test!(@generate_size (0..8)) }; + (@generate_size ($sizes:expr)) => { $sizes.into_iter().map(Into::::into) }; + // Generate sizes for !Sized types. + (@generate_size ($min_sizes:tt, $elem_sizes:tt)) => { + itertools::iproduct!( + test!(@generate_min_size $min_sizes), + test!(@generate_elem_size $elem_sizes) + ).map(Into::::into) + }; + (@generate_fixed_size _) => { (0..8).into_iter().map(Into::::into) }; + (@generate_min_size _) => { 0..8 }; + (@generate_elem_size _) => { 1..8 }; + (@generate_align _) => { [1, 2, 4, 8, 16] }; + (@generate_opt_usize _) => { [None].into_iter().chain((0..8).map(Some).into_iter()) }; + (@generate_cast_type _) => { [_CastType::_Prefix, _CastType::_Suffix] }; + (@generate_cast_type $variant:ident) => { [_CastType::$variant] }; + // Some expressions need to be wrapped in parentheses in order to be + // valid `tt`s (required by the top match pattern). See the comment + // below for more details. This arm removes these parentheses to + // avoid generating an `unused_parens` warning. + (@$_:ident ($vals:expr)) => { $vals }; + (@$_:ident $vals:expr) => { $vals }; + } + + const EVENS: [usize; 8] = [0, 2, 4, 6, 8, 10, 12, 14]; + const ODDS: [usize; 8] = [1, 3, 5, 7, 9, 11, 13, 15]; + + // base_size is too big for the memory region. + test!(layout(((1..8) | ((1..8), (1..8))), _).validate(_, [0], _), Ok(None)); + test!(layout(((2..8) | ((2..8), (2..8))), _).validate(_, [1], _), Ok(None)); + + // addr is unaligned for prefix cast + test!(layout(_, [2]).validate(ODDS, _, _Prefix), Ok(None)); + test!(layout(_, [2]).validate(ODDS, _, _Prefix), Ok(None)); + + // addr is aligned, but end of buffer is unaligned for suffix cast + test!(layout(_, [2]).validate(EVENS, ODDS, _Suffix), Ok(None)); + test!(layout(_, [2]).validate(EVENS, ODDS, _Suffix), Ok(None)); + + // Unfortunately, these constants cannot easily be used in the + // implementation of `validate_cast_and_convert_metadata`, since + // `panic!` consumes a string literal, not an expression. + // + // It's important that these messages be in a separate module. If they + // were at the function's top level, we'd pass them to `test!` as, e.g., + // `Err(TRAILING)`, which would run into a subtle Rust footgun - the + // `TRAILING` identifier would be treated as a pattern to match rather + // than a value to check for equality. + mod msgs { + pub(super) const TRAILING: &str = + "attempted to cast to slice type with zero-sized element"; + pub(super) const OVERFLOW: &str = "`addr` + `bytes_len` > usize::MAX"; + } + + // casts with ZST trailing element types are unsupported + test!(layout((_, [0]), _).validate(_, _, _), Err(msgs::TRAILING),); + + // addr + bytes_len must not overflow usize + test!(layout(_, _).validate([usize::MAX], (1..100), _), Err(msgs::OVERFLOW)); + test!(layout(_, _).validate((1..100), [usize::MAX], _), Err(msgs::OVERFLOW)); + test!( + layout(_, _).validate( + [usize::MAX / 2 + 1, usize::MAX], + [usize::MAX / 2 + 1, usize::MAX], + _ + ), + Err(msgs::OVERFLOW) + ); + + // Validates that `validate_cast_and_convert_metadata` satisfies its own + // documented safety postconditions, and also a few other properties + // that aren't documented but we want to guarantee anyway. + fn validate_behavior( + (layout, addr, bytes_len, cast_type): (DstLayout, usize, usize, _CastType), + ) { + if let Some((elems, split_at)) = + layout.validate_cast_and_convert_metadata(addr, bytes_len, cast_type) + { + let (size_info, align) = (layout.size_info, layout.align); + let debug_str = format!( + "layout({size_info:?}, {align}).validate_cast_and_convert_metadata({addr}, {bytes_len}, {cast_type:?}) => ({elems}, {split_at})", + ); + + // If this is a sized type (no trailing slice), then `elems` is + // meaningless, but in practice we set it to 0. Callers are not + // allowed to rely on this, but a lot of math is nicer if + // they're able to, and some callers might accidentally do that. + let sized = matches!(layout.size_info, SizeInfo::Sized { .. }); + assert!(!(sized && elems != 0), "{}", debug_str); + + let resulting_size = match layout.size_info { + SizeInfo::Sized { _size } => _size, + SizeInfo::SliceDst(TrailingSliceLayout { + _offset: offset, + _elem_size: elem_size, + }) => { + let padded_size = |elems| { + let without_padding = offset + elems * elem_size; + without_padding + + util::core_layout::padding_needed_for(without_padding, align) + }; + + let resulting_size = padded_size(elems); + // Test that `validate_cast_and_convert_metadata` + // computed the largest possible value that fits in the + // given range. + assert!(padded_size(elems + 1) > bytes_len, "{}", debug_str); + resulting_size + } + }; + + // Test safety postconditions guaranteed by + // `validate_cast_and_convert_metadata`. + assert!(resulting_size <= bytes_len, "{}", debug_str); + match cast_type { + _CastType::_Prefix => { + assert_eq!(addr % align, 0, "{}", debug_str); + assert_eq!(resulting_size, split_at, "{}", debug_str); + } + _CastType::_Suffix => { + assert_eq!(split_at, bytes_len - resulting_size, "{}", debug_str); + assert_eq!((addr + split_at) % align, 0, "{}", debug_str); + } + } + } else { + let min_size = match layout.size_info { + SizeInfo::Sized { _size } => _size, + SizeInfo::SliceDst(TrailingSliceLayout { _offset, .. }) => { + _offset + util::core_layout::padding_needed_for(_offset, layout.align) + } + }; + + // If a cast is invalid, it is either because... + // 1. there are insufficent bytes at the given region for type: + let insufficient_bytes = bytes_len < min_size; + // 2. performing the cast would misalign type: + let base = match cast_type { + _CastType::_Prefix => 0, + _CastType::_Suffix => bytes_len, + }; + let misaligned = (base + addr) % layout.align != 0; + + assert!(insufficient_bytes || misaligned); + } + } + + let sizes = 0..8; + let elem_sizes = 1..8; + let size_infos = sizes + .clone() + .map(Into::::into) + .chain(itertools::iproduct!(sizes, elem_sizes).map(Into::::into)); + let layouts = itertools::iproduct!(size_infos, [1, 2, 4, 8, 16, 32]) + .filter(|(size_info, align)| !matches!(size_info, SizeInfo::Sized { _size } if _size % align != 0)) + .map(|(size_info, align)| layout(size_info, align)); + itertools::iproduct!(layouts, 0..8, 0..8, [_CastType::_Prefix, _CastType::_Suffix]) + .for_each(validate_behavior); + } + + #[test] + #[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)] + fn test_validate_rust_layout() { + use core::ptr::NonNull; + + // This test synthesizes pointers with various metadata and uses Rust's + // built-in APIs to confirm that Rust makes decisions about type layout + // which are consistent with what we believe is guaranteed by the + // language. If this test fails, it doesn't just mean our code is wrong + // - it means we're misunderstanding the language's guarantees. + + #[derive(Debug)] + struct MacroArgs { + offset: usize, + align: NonZeroUsize, + elem_size: Option, + } + + /// # Safety + /// + /// `test` promises to only call `addr_of_slice_field` on a `NonNull` + /// which points to a valid `T`. + /// + /// `with_elems` must produce a pointer which points to a valid `T`. + fn test NonNull>( + args: MacroArgs, + with_elems: W, + addr_of_slice_field: Option) -> NonNull>, + ) { + let dst = args.elem_size.is_some(); + let layout = { + let size_info = match args.elem_size { + Some(elem_size) => SizeInfo::SliceDst(TrailingSliceLayout { + _offset: args.offset, + _elem_size: elem_size, + }), + None => SizeInfo::Sized { + // Rust only supports types whose sizes are a multiple + // of their alignment. If the macro created a type like + // this: + // + // #[repr(C, align(2))] + // struct Foo([u8; 1]); + // + // ...then Rust will automatically round the type's size + // up to 2. + _size: args.offset + + util::core_layout::padding_needed_for(args.offset, args.align), + }, + }; + DstLayout { size_info, align: args.align } + }; + + for elems in 0..128 { + let ptr = with_elems(elems); + + if let Some(addr_of_slice_field) = addr_of_slice_field { + let slc_field_ptr = addr_of_slice_field(ptr).as_ptr(); + // SAFETY: Both `slc_field_ptr` and `ptr` are pointers to + // the same valid Rust object. + let offset: usize = + unsafe { slc_field_ptr.byte_offset_from(ptr.as_ptr()).try_into().unwrap() }; + assert_eq!(offset, args.offset); + } + + // SAFETY: `ptr` points to a valid `T`. + let (size, align) = unsafe { + (mem::size_of_val_raw(ptr.as_ptr()), mem::align_of_val_raw(ptr.as_ptr())) + }; + + // Avoid expensive allocation when running under Miri. + let assert_msg = if !cfg!(miri) { + format!("\n{args:?}\nsize:{size}, align:{align}") + } else { + String::new() + }; + + let without_padding = + args.offset + args.elem_size.map(|elem_size| elems * elem_size).unwrap_or(0); + assert!(size >= without_padding, "{}", assert_msg); + assert_eq!(align, args.align.get(), "{}", assert_msg); + + // This encodes the most important part of the test: our + // understanding of how Rust determines the layout of repr(C) + // types. Sized repr(C) types are trivial, but DST types have + // some subtlety. Note that: + // - For sized types, `without_padding` is just the size of the + // type that we constructed for `Foo`. Since we may have + // requested a larger alignment, `Foo` may actually be larger + // than this, hence `padding_needed_for`. + // - For unsized types, `without_padding` is dynamically + // computed from the offset, the element size, and element + // count. We expect that the size of the object should be + // `offset + elem_size * elems` rounded up to the next + // alignment. + let expected_size = without_padding + + util::core_layout::padding_needed_for(without_padding, args.align); + assert_eq!(expected_size, size, "{}", assert_msg); + + // For zero-sized element types, + // `validate_cast_and_convert_metadata` just panics, so we skip + // testing those types. + if args.elem_size.map(|elem_size| elem_size > 0).unwrap_or(true) { + let addr = ptr.addr().get(); + let (got_elems, got_split_at) = layout + .validate_cast_and_convert_metadata(addr, size, _CastType::_Prefix) + .unwrap(); + // Avoid expensive allocation when running under Miri. + let assert_msg = if !cfg!(miri) { + format!( + "{}\nvalidate_cast_and_convert_metadata({addr}, {size})", + assert_msg + ) + } else { + String::new() + }; + assert_eq!(got_split_at, size, "{}", assert_msg); + if dst { + assert!(got_elems >= elems, "{}", assert_msg); + if got_elems != elems { + // If `validate_cast_and_convert_metadata` + // returned more elements than `elems`, that + // means that `elems` is not the maximum number + // of elements that can fit in `size` - in other + // words, there is enough padding at the end of + // the value to fit at least one more element. + // If we use this metadata to synthesize a + // pointer, despite having a different element + // count, we still expect it to have the same + // size. + let got_ptr = with_elems(got_elems); + // SAFETY: `got_ptr` is a pointer to a valid `T`. + let size_of_got_ptr = unsafe { mem::size_of_val_raw(got_ptr.as_ptr()) }; + assert_eq!(size_of_got_ptr, size, "{}", assert_msg); + } + } else { + // For sized casts, the returned element value is + // technically meaningless, and we don't guarantee any + // particular value. In practice, it's always zero. + assert_eq!(got_elems, 0, "{}", assert_msg) + } + } + } + } + + macro_rules! validate_against_rust { + ($offset:literal, $align:literal $(, $elem_size:literal)?) => {{ + #[repr(C, align($align))] + struct Foo([u8; $offset]$(, [[u8; $elem_size]])?); + + let args = MacroArgs { + offset: $offset, + align: $align.try_into().unwrap(), + elem_size: { + #[allow(unused)] + let ret = None::; + $(let ret = Some($elem_size);)? + ret + } + }; + + #[repr(C, align($align))] + struct FooAlign; + // Create an aligned buffer to use in order to synthesize + // pointers to `Foo`. We don't ever load values from these + // pointers - we just do arithmetic on them - so having a "real" + // block of memory as opposed to a validly-aligned-but-dangling + // pointer is only necessary to make Miri happy since we run it + // with "strict provenance" checking enabled. + let aligned_buf = Align::<_, FooAlign>::new([0u8; 1024]); + let with_elems = |elems| { + let slc = NonNull::slice_from_raw_parts(NonNull::from(&aligned_buf.t), elems); + #[allow(clippy::as_conversions)] + NonNull::new(slc.as_ptr() as *mut Foo).unwrap() + }; + let addr_of_slice_field = { + #[allow(unused)] + let f = None::) -> NonNull>; + $( + // SAFETY: `test` promises to only call `f` with a `ptr` + // to a valid `Foo`. + let f: Option) -> NonNull> = Some(|ptr: NonNull| unsafe { + NonNull::new(ptr::addr_of_mut!((*ptr.as_ptr()).1)).unwrap().cast::() + }); + let _ = $elem_size; + )? + f + }; + + test::(args, with_elems, addr_of_slice_field); + }}; + } + + // Every permutation of: + // - offset in [0, 4] + // - align in [1, 16] + // - elem_size in [0, 4] (plus no elem_size) + validate_against_rust!(0, 1); + validate_against_rust!(0, 1, 0); + validate_against_rust!(0, 1, 1); + validate_against_rust!(0, 1, 2); + validate_against_rust!(0, 1, 3); + validate_against_rust!(0, 1, 4); + validate_against_rust!(0, 2); + validate_against_rust!(0, 2, 0); + validate_against_rust!(0, 2, 1); + validate_against_rust!(0, 2, 2); + validate_against_rust!(0, 2, 3); + validate_against_rust!(0, 2, 4); + validate_against_rust!(0, 4); + validate_against_rust!(0, 4, 0); + validate_against_rust!(0, 4, 1); + validate_against_rust!(0, 4, 2); + validate_against_rust!(0, 4, 3); + validate_against_rust!(0, 4, 4); + validate_against_rust!(0, 8); + validate_against_rust!(0, 8, 0); + validate_against_rust!(0, 8, 1); + validate_against_rust!(0, 8, 2); + validate_against_rust!(0, 8, 3); + validate_against_rust!(0, 8, 4); + validate_against_rust!(0, 16); + validate_against_rust!(0, 16, 0); + validate_against_rust!(0, 16, 1); + validate_against_rust!(0, 16, 2); + validate_against_rust!(0, 16, 3); + validate_against_rust!(0, 16, 4); + validate_against_rust!(1, 1); + validate_against_rust!(1, 1, 0); + validate_against_rust!(1, 1, 1); + validate_against_rust!(1, 1, 2); + validate_against_rust!(1, 1, 3); + validate_against_rust!(1, 1, 4); + validate_against_rust!(1, 2); + validate_against_rust!(1, 2, 0); + validate_against_rust!(1, 2, 1); + validate_against_rust!(1, 2, 2); + validate_against_rust!(1, 2, 3); + validate_against_rust!(1, 2, 4); + validate_against_rust!(1, 4); + validate_against_rust!(1, 4, 0); + validate_against_rust!(1, 4, 1); + validate_against_rust!(1, 4, 2); + validate_against_rust!(1, 4, 3); + validate_against_rust!(1, 4, 4); + validate_against_rust!(1, 8); + validate_against_rust!(1, 8, 0); + validate_against_rust!(1, 8, 1); + validate_against_rust!(1, 8, 2); + validate_against_rust!(1, 8, 3); + validate_against_rust!(1, 8, 4); + validate_against_rust!(1, 16); + validate_against_rust!(1, 16, 0); + validate_against_rust!(1, 16, 1); + validate_against_rust!(1, 16, 2); + validate_against_rust!(1, 16, 3); + validate_against_rust!(1, 16, 4); + validate_against_rust!(2, 1); + validate_against_rust!(2, 1, 0); + validate_against_rust!(2, 1, 1); + validate_against_rust!(2, 1, 2); + validate_against_rust!(2, 1, 3); + validate_against_rust!(2, 1, 4); + validate_against_rust!(2, 2); + validate_against_rust!(2, 2, 0); + validate_against_rust!(2, 2, 1); + validate_against_rust!(2, 2, 2); + validate_against_rust!(2, 2, 3); + validate_against_rust!(2, 2, 4); + validate_against_rust!(2, 4); + validate_against_rust!(2, 4, 0); + validate_against_rust!(2, 4, 1); + validate_against_rust!(2, 4, 2); + validate_against_rust!(2, 4, 3); + validate_against_rust!(2, 4, 4); + validate_against_rust!(2, 8); + validate_against_rust!(2, 8, 0); + validate_against_rust!(2, 8, 1); + validate_against_rust!(2, 8, 2); + validate_against_rust!(2, 8, 3); + validate_against_rust!(2, 8, 4); + validate_against_rust!(2, 16); + validate_against_rust!(2, 16, 0); + validate_against_rust!(2, 16, 1); + validate_against_rust!(2, 16, 2); + validate_against_rust!(2, 16, 3); + validate_against_rust!(2, 16, 4); + validate_against_rust!(3, 1); + validate_against_rust!(3, 1, 0); + validate_against_rust!(3, 1, 1); + validate_against_rust!(3, 1, 2); + validate_against_rust!(3, 1, 3); + validate_against_rust!(3, 1, 4); + validate_against_rust!(3, 2); + validate_against_rust!(3, 2, 0); + validate_against_rust!(3, 2, 1); + validate_against_rust!(3, 2, 2); + validate_against_rust!(3, 2, 3); + validate_against_rust!(3, 2, 4); + validate_against_rust!(3, 4); + validate_against_rust!(3, 4, 0); + validate_against_rust!(3, 4, 1); + validate_against_rust!(3, 4, 2); + validate_against_rust!(3, 4, 3); + validate_against_rust!(3, 4, 4); + validate_against_rust!(3, 8); + validate_against_rust!(3, 8, 0); + validate_against_rust!(3, 8, 1); + validate_against_rust!(3, 8, 2); + validate_against_rust!(3, 8, 3); + validate_against_rust!(3, 8, 4); + validate_against_rust!(3, 16); + validate_against_rust!(3, 16, 0); + validate_against_rust!(3, 16, 1); + validate_against_rust!(3, 16, 2); + validate_against_rust!(3, 16, 3); + validate_against_rust!(3, 16, 4); + validate_against_rust!(4, 1); + validate_against_rust!(4, 1, 0); + validate_against_rust!(4, 1, 1); + validate_against_rust!(4, 1, 2); + validate_against_rust!(4, 1, 3); + validate_against_rust!(4, 1, 4); + validate_against_rust!(4, 2); + validate_against_rust!(4, 2, 0); + validate_against_rust!(4, 2, 1); + validate_against_rust!(4, 2, 2); + validate_against_rust!(4, 2, 3); + validate_against_rust!(4, 2, 4); + validate_against_rust!(4, 4); + validate_against_rust!(4, 4, 0); + validate_against_rust!(4, 4, 1); + validate_against_rust!(4, 4, 2); + validate_against_rust!(4, 4, 3); + validate_against_rust!(4, 4, 4); + validate_against_rust!(4, 8); + validate_against_rust!(4, 8, 0); + validate_against_rust!(4, 8, 1); + validate_against_rust!(4, 8, 2); + validate_against_rust!(4, 8, 3); + validate_against_rust!(4, 8, 4); + validate_against_rust!(4, 16); + validate_against_rust!(4, 16, 0); + validate_against_rust!(4, 16, 1); + validate_against_rust!(4, 16, 2); + validate_against_rust!(4, 16, 3); + validate_against_rust!(4, 16, 4); + } + + #[test] + fn test_known_layout() { + // Test that `$ty` and `ManuallyDrop<$ty>` have the expected layout. + // Test that `PhantomData<$ty>` has the same layout as `()` regardless + // of `$ty`. + macro_rules! test { + ($ty:ty, $expect:expr) => { + let expect = $expect; + assert_eq!(<$ty as KnownLayout>::LAYOUT, expect); + assert_eq!( as KnownLayout>::LAYOUT, expect); + assert_eq!( as KnownLayout>::LAYOUT, <() as KnownLayout>::LAYOUT); + }; + } + + let layout = |offset, align, _trailing_slice_elem_size| DstLayout { + align: NonZeroUsize::new(align).unwrap(), + size_info: match _trailing_slice_elem_size { + None => SizeInfo::Sized { _size: offset }, + Some(elem_size) => SizeInfo::SliceDst(TrailingSliceLayout { + _offset: offset, + _elem_size: elem_size, + }), + }, + }; + + test!((), layout(0, 1, None)); + test!(u8, layout(1, 1, None)); + // Use `align_of` because `u64` alignment may be smaller than 8 on some + // platforms. + test!(u64, layout(8, mem::align_of::(), None)); + test!(AU64, layout(8, 8, None)); + + test!(Option<&'static ()>, usize::LAYOUT); + + test!([()], layout(0, 1, Some(0))); + test!([u8], layout(0, 1, Some(1))); + test!(str, layout(0, 1, Some(1))); + } + + #[cfg(feature = "derive")] + #[test] + fn test_known_layout_derive() { + // In this and other files (`late_compile_pass.rs`, + // `mid_compile_pass.rs`, and `struct.rs`), we test success and failure + // modes of `derive(KnownLayout)` for the following combination of + // properties: + // + // +------------+--------------------------------------+-----------+ + // | | trailing field properties | | + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // |------------+----------+----------------+----------+-----------| + // | N | N | N | N | KL00 | + // | N | N | N | Y | KL01 | + // | N | N | Y | N | KL02 | + // | N | N | Y | Y | KL03 | + // | N | Y | N | N | KL04 | + // | N | Y | N | Y | KL05 | + // | N | Y | Y | N | KL06 | + // | N | Y | Y | Y | KL07 | + // | Y | N | N | N | KL08 | + // | Y | N | N | Y | KL09 | + // | Y | N | Y | N | KL10 | + // | Y | N | Y | Y | KL11 | + // | Y | Y | N | N | KL12 | + // | Y | Y | N | Y | KL13 | + // | Y | Y | Y | N | KL14 | + // | Y | Y | Y | Y | KL15 | + // +------------+----------+----------------+----------+-----------+ + + struct NotKnownLayout { + _t: T, + } + + #[derive(KnownLayout)] + #[repr(C)] + struct AlignSize + where + elain::Align: elain::Alignment, + { + _align: elain::Align, + _size: [u8; SIZE], + } + + type AU16 = AlignSize<2, 2>; + type AU32 = AlignSize<4, 4>; + + fn _assert_kl(_: &T) {} + + let sized_layout = |align, size| DstLayout { + align: NonZeroUsize::new(align).unwrap(), + size_info: SizeInfo::Sized { _size: size }, + }; + + let unsized_layout = |align, elem_size, offset| DstLayout { + align: NonZeroUsize::new(align).unwrap(), + size_info: SizeInfo::SliceDst(TrailingSliceLayout { + _offset: offset, + _elem_size: elem_size, + }), + }; + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | N | N | N | Y | KL01 | + #[derive(KnownLayout)] + struct KL01(NotKnownLayout, NotKnownLayout); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(4, 8)); + + // ...with `align(N)`: + #[derive(KnownLayout)] + #[repr(align(64))] + struct KL01Align(NotKnownLayout, NotKnownLayout); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(64, 64)); + + // ...with `packed`: + #[derive(KnownLayout)] + #[repr(packed)] + struct KL01Packed(NotKnownLayout, NotKnownLayout); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(1, 6)); + + // ...with `packed(N)`: + #[derive(KnownLayout)] + #[repr(packed(2))] + struct KL01PackedN(NotKnownLayout, NotKnownLayout); + + assert_impl_all!(KL01PackedN: KnownLayout); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(2, 6)); + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | N | N | Y | Y | KL03 | + #[derive(KnownLayout)] + struct KL03(NotKnownLayout, u8); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(1, 1)); + + // ... with `align(N)` + #[derive(KnownLayout)] + #[repr(align(64))] + struct KL03Align(NotKnownLayout, u8); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(64, 64)); + + // ... with `packed`: + #[derive(KnownLayout)] + #[repr(packed)] + struct KL03Packed(NotKnownLayout, u8); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(1, 5)); + + // ... with `packed(N)` + #[derive(KnownLayout)] + #[repr(packed(2))] + struct KL03PackedN(NotKnownLayout, u8); + + assert_impl_all!(KL03PackedN: KnownLayout); + + let expected = DstLayout::for_type::(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(2, 6)); + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | N | Y | N | Y | KL05 | + #[derive(KnownLayout)] + struct KL05(u8, T); + + fn _test_kl05(t: T) -> impl KnownLayout { + KL05(0u8, t) + } + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | N | Y | Y | Y | KL07 | + #[derive(KnownLayout)] + struct KL07(u8, T); + + fn _test_kl07(t: T) -> impl KnownLayout { + let _ = KL07(0u8, t); + } + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | Y | N | Y | N | KL10 | + #[derive(KnownLayout)] + #[repr(C)] + struct KL10(NotKnownLayout, [u8]); + + let expected = DstLayout::new_zst(None) + .extend(DstLayout::for_type::>(), None) + .extend(<[u8] as KnownLayout>::LAYOUT, None) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, unsized_layout(4, 1, 4)); + + // ...with `align(N)`: + #[derive(KnownLayout)] + #[repr(C, align(64))] + struct KL10Align(NotKnownLayout, [u8]); + + let repr_align = NonZeroUsize::new(64); + + let expected = DstLayout::new_zst(repr_align) + .extend(DstLayout::for_type::>(), None) + .extend(<[u8] as KnownLayout>::LAYOUT, None) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, unsized_layout(64, 1, 4)); + + // ...with `packed`: + #[derive(KnownLayout)] + #[repr(C, packed)] + struct KL10Packed(NotKnownLayout, [u8]); + + let repr_packed = NonZeroUsize::new(1); + + let expected = DstLayout::new_zst(None) + .extend(DstLayout::for_type::>(), repr_packed) + .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, unsized_layout(1, 1, 4)); + + // ...with `packed(N)`: + #[derive(KnownLayout)] + #[repr(C, packed(2))] + struct KL10PackedN(NotKnownLayout, [u8]); + + let repr_packed = NonZeroUsize::new(2); + + let expected = DstLayout::new_zst(None) + .extend(DstLayout::for_type::>(), repr_packed) + .extend(<[u8] as KnownLayout>::LAYOUT, repr_packed) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, unsized_layout(2, 1, 4)); + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | Y | N | Y | Y | KL11 | + #[derive(KnownLayout)] + #[repr(C)] + struct KL11(NotKnownLayout, u8); + + let expected = DstLayout::new_zst(None) + .extend(DstLayout::for_type::>(), None) + .extend(::LAYOUT, None) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(8, 16)); + + // ...with `align(N)`: + #[derive(KnownLayout)] + #[repr(C, align(64))] + struct KL11Align(NotKnownLayout, u8); + + let repr_align = NonZeroUsize::new(64); + + let expected = DstLayout::new_zst(repr_align) + .extend(DstLayout::for_type::>(), None) + .extend(::LAYOUT, None) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(64, 64)); + + // ...with `packed`: + #[derive(KnownLayout)] + #[repr(C, packed)] + struct KL11Packed(NotKnownLayout, u8); + + let repr_packed = NonZeroUsize::new(1); + + let expected = DstLayout::new_zst(None) + .extend(DstLayout::for_type::>(), repr_packed) + .extend(::LAYOUT, repr_packed) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(1, 9)); + + // ...with `packed(N)`: + #[derive(KnownLayout)] + #[repr(C, packed(2))] + struct KL11PackedN(NotKnownLayout, u8); + + let repr_packed = NonZeroUsize::new(2); + + let expected = DstLayout::new_zst(None) + .extend(DstLayout::for_type::>(), repr_packed) + .extend(::LAYOUT, repr_packed) + .pad_to_align(); + + assert_eq!(::LAYOUT, expected); + assert_eq!(::LAYOUT, sized_layout(2, 10)); + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | Y | Y | Y | N | KL14 | + #[derive(KnownLayout)] + #[repr(C)] + struct KL14(u8, T); + + fn _test_kl14(kl: &KL14) { + _assert_kl(kl) + } + + // | `repr(C)`? | generic? | `KnownLayout`? | `Sized`? | Type Name | + // | Y | Y | Y | Y | KL15 | + #[derive(KnownLayout)] + #[repr(C)] + struct KL15(u8, T); + + fn _test_kl15(t: T) -> impl KnownLayout { + let _ = KL15(0u8, t); + } + + // Test a variety of combinations of field types: + // - () + // - u8 + // - AU16 + // - [()] + // - [u8] + // - [AU16] + + #[allow(clippy::upper_case_acronyms)] + #[derive(KnownLayout)] + #[repr(C)] + struct KLTU(T, U); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(1, 0)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(1, 1)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 2)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(1, 0, 0)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(1, 1, 0)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 2, 0)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(1, 1)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(1, 2)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 4)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(1, 0, 1)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(1, 1, 1)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 2, 2)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 2)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 4)); + + assert_eq!( as KnownLayout>::LAYOUT, sized_layout(2, 4)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 0, 2)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 1, 2)); + + assert_eq!( as KnownLayout>::LAYOUT, unsized_layout(2, 2, 2)); + + // Test a variety of field counts. + + #[derive(KnownLayout)] + #[repr(C)] + struct KLF0; + + assert_eq!(::LAYOUT, sized_layout(1, 0)); + + #[derive(KnownLayout)] + #[repr(C)] + struct KLF1([u8]); + + assert_eq!(::LAYOUT, unsized_layout(1, 1, 0)); + + #[derive(KnownLayout)] + #[repr(C)] + struct KLF2(NotKnownLayout, [u8]); + + assert_eq!(::LAYOUT, unsized_layout(1, 1, 1)); + + #[derive(KnownLayout)] + #[repr(C)] + struct KLF3(NotKnownLayout, NotKnownLayout, [u8]); + + assert_eq!(::LAYOUT, unsized_layout(2, 1, 4)); + + #[derive(KnownLayout)] + #[repr(C)] + struct KLF4(NotKnownLayout, NotKnownLayout, NotKnownLayout, [u8]); + + assert_eq!(::LAYOUT, unsized_layout(4, 1, 8)); + } + + #[test] + fn test_object_safety() { + fn _takes_from_zeroes(_: &dyn FromZeroes) {} + fn _takes_from_bytes(_: &dyn FromBytes) {} + fn _takes_unaligned(_: &dyn Unaligned) {} + } + + #[test] + fn test_from_zeroes_only() { + // Test types that implement `FromZeroes` but not `FromBytes`. + + assert!(!bool::new_zeroed()); + assert_eq!(char::new_zeroed(), '\0'); + + #[cfg(feature = "alloc")] + { + assert_eq!(bool::new_box_zeroed(), Box::new(false)); + assert_eq!(char::new_box_zeroed(), Box::new('\0')); + + assert_eq!(bool::new_box_slice_zeroed(3).as_ref(), [false, false, false]); + assert_eq!(char::new_box_slice_zeroed(3).as_ref(), ['\0', '\0', '\0']); + + assert_eq!(bool::new_vec_zeroed(3).as_ref(), [false, false, false]); + assert_eq!(char::new_vec_zeroed(3).as_ref(), ['\0', '\0', '\0']); + } + + let mut string = "hello".to_string(); + let s: &mut str = string.as_mut(); + assert_eq!(s, "hello"); + s.zero(); + assert_eq!(s, "\0\0\0\0\0"); + } + + #[test] + fn test_read_write() { + const VAL: u64 = 0x12345678; + #[cfg(target_endian = "big")] + const VAL_BYTES: [u8; 8] = VAL.to_be_bytes(); + #[cfg(target_endian = "little")] + const VAL_BYTES: [u8; 8] = VAL.to_le_bytes(); + + // Test `FromBytes::{read_from, read_from_prefix, read_from_suffix}`. + + assert_eq!(u64::read_from(&VAL_BYTES[..]), Some(VAL)); + // The first 8 bytes are from `VAL_BYTES` and the second 8 bytes are all + // zeroes. + let bytes_with_prefix: [u8; 16] = transmute!([VAL_BYTES, [0; 8]]); + assert_eq!(u64::read_from_prefix(&bytes_with_prefix[..]), Some(VAL)); + assert_eq!(u64::read_from_suffix(&bytes_with_prefix[..]), Some(0)); + // The first 8 bytes are all zeroes and the second 8 bytes are from + // `VAL_BYTES` + let bytes_with_suffix: [u8; 16] = transmute!([[0; 8], VAL_BYTES]); + assert_eq!(u64::read_from_prefix(&bytes_with_suffix[..]), Some(0)); + assert_eq!(u64::read_from_suffix(&bytes_with_suffix[..]), Some(VAL)); + + // Test `AsBytes::{write_to, write_to_prefix, write_to_suffix}`. + + let mut bytes = [0u8; 8]; + assert_eq!(VAL.write_to(&mut bytes[..]), Some(())); + assert_eq!(bytes, VAL_BYTES); + let mut bytes = [0u8; 16]; + assert_eq!(VAL.write_to_prefix(&mut bytes[..]), Some(())); + let want: [u8; 16] = transmute!([VAL_BYTES, [0; 8]]); + assert_eq!(bytes, want); + let mut bytes = [0u8; 16]; + assert_eq!(VAL.write_to_suffix(&mut bytes[..]), Some(())); + let want: [u8; 16] = transmute!([[0; 8], VAL_BYTES]); + assert_eq!(bytes, want); + } + + #[test] + fn test_transmute() { + // Test that memory is transmuted as expected. + let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; + let x: [[u8; 2]; 4] = transmute!(array_of_u8s); + assert_eq!(x, array_of_arrays); + let x: [u8; 8] = transmute!(array_of_arrays); + assert_eq!(x, array_of_u8s); + + // Test that the source expression's value is forgotten rather than + // dropped. + #[derive(AsBytes)] + #[repr(transparent)] + struct PanicOnDrop(()); + impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!("PanicOnDrop::drop"); + } + } + #[allow(clippy::let_unit_value)] + let _: () = transmute!(PanicOnDrop(())); + + // Test that `transmute!` is legal in a const context. + const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7]; + const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]]; + const X: [[u8; 2]; 4] = transmute!(ARRAY_OF_U8S); + assert_eq!(X, ARRAY_OF_ARRAYS); + } + + #[test] + fn test_transmute_ref() { + // Test that memory is transmuted as expected. + let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; + let x: &[[u8; 2]; 4] = transmute_ref!(&array_of_u8s); + assert_eq!(*x, array_of_arrays); + let x: &[u8; 8] = transmute_ref!(&array_of_arrays); + assert_eq!(*x, array_of_u8s); + + // Test that `transmute_ref!` is legal in a const context. + const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7]; + const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]]; + #[allow(clippy::redundant_static_lifetimes)] + const X: &'static [[u8; 2]; 4] = transmute_ref!(&ARRAY_OF_U8S); + assert_eq!(*X, ARRAY_OF_ARRAYS); + + // Test that it's legal to transmute a reference while shrinking the + // lifetime (note that `X` has the lifetime `'static`). + let x: &[u8; 8] = transmute_ref!(X); + assert_eq!(*x, ARRAY_OF_U8S); + + // Test that `transmute_ref!` supports decreasing alignment. + let u = AU64(0); + let array = [0, 0, 0, 0, 0, 0, 0, 0]; + let x: &[u8; 8] = transmute_ref!(&u); + assert_eq!(*x, array); + + // Test that a mutable reference can be turned into an immutable one. + let mut x = 0u8; + #[allow(clippy::useless_transmute)] + let y: &u8 = transmute_ref!(&mut x); + assert_eq!(*y, 0); + } + + #[test] + fn test_transmute_mut() { + // Test that memory is transmuted as expected. + let mut array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; + let x: &mut [[u8; 2]; 4] = transmute_mut!(&mut array_of_u8s); + assert_eq!(*x, array_of_arrays); + let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays); + assert_eq!(*x, array_of_u8s); + + { + // Test that it's legal to transmute a reference while shrinking the + // lifetime. + let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays); + assert_eq!(*x, array_of_u8s); + } + // Test that `transmute_mut!` supports decreasing alignment. + let mut u = AU64(0); + let array = [0, 0, 0, 0, 0, 0, 0, 0]; + let x: &[u8; 8] = transmute_mut!(&mut u); + assert_eq!(*x, array); + + // Test that a mutable reference can be turned into an immutable one. + let mut x = 0u8; + #[allow(clippy::useless_transmute)] + let y: &u8 = transmute_mut!(&mut x); + assert_eq!(*y, 0); + } + + #[test] + fn test_macros_evaluate_args_once() { + let mut ctr = 0; + let _: usize = transmute!({ + ctr += 1; + 0usize + }); + assert_eq!(ctr, 1); + + let mut ctr = 0; + let _: &usize = transmute_ref!({ + ctr += 1; + &0usize + }); + assert_eq!(ctr, 1); + } + + #[test] + fn test_include_value() { + const AS_U32: u32 = include_value!("../testdata/include_value/data"); + assert_eq!(AS_U32, u32::from_ne_bytes([b'a', b'b', b'c', b'd'])); + const AS_I32: i32 = include_value!("../testdata/include_value/data"); + assert_eq!(AS_I32, i32::from_ne_bytes([b'a', b'b', b'c', b'd'])); + } + + #[test] + fn test_address() { + // Test that the `Deref` and `DerefMut` implementations return a + // reference which points to the right region of memory. + + let buf = [0]; + let r = Ref::<_, u8>::new(&buf[..]).unwrap(); + let buf_ptr = buf.as_ptr(); + let deref_ptr: *const u8 = r.deref(); + assert_eq!(buf_ptr, deref_ptr); + + let buf = [0]; + let r = Ref::<_, [u8]>::new_slice(&buf[..]).unwrap(); + let buf_ptr = buf.as_ptr(); + let deref_ptr = r.deref().as_ptr(); + assert_eq!(buf_ptr, deref_ptr); + } + + // Verify that values written to a `Ref` are properly shared between the + // typed and untyped representations, that reads via `deref` and `read` + // behave the same, and that writes via `deref_mut` and `write` behave the + // same. + fn test_new_helper(mut r: Ref<&mut [u8], AU64>) { + // assert that the value starts at 0 + assert_eq!(*r, AU64(0)); + assert_eq!(r.read(), AU64(0)); + + // Assert that values written to the typed value are reflected in the + // byte slice. + const VAL1: AU64 = AU64(0xFF00FF00FF00FF00); + *r = VAL1; + assert_eq!(r.bytes(), &VAL1.to_bytes()); + *r = AU64(0); + r.write(VAL1); + assert_eq!(r.bytes(), &VAL1.to_bytes()); + + // Assert that values written to the byte slice are reflected in the + // typed value. + const VAL2: AU64 = AU64(!VAL1.0); // different from `VAL1` + r.bytes_mut().copy_from_slice(&VAL2.to_bytes()[..]); + assert_eq!(*r, VAL2); + assert_eq!(r.read(), VAL2); + } + + // Verify that values written to a `Ref` are properly shared between the + // typed and untyped representations; pass a value with `typed_len` `AU64`s + // backed by an array of `typed_len * 8` bytes. + fn test_new_helper_slice(mut r: Ref<&mut [u8], [AU64]>, typed_len: usize) { + // Assert that the value starts out zeroed. + assert_eq!(&*r, vec![AU64(0); typed_len].as_slice()); + + // Check the backing storage is the exact same slice. + let untyped_len = typed_len * 8; + assert_eq!(r.bytes().len(), untyped_len); + assert_eq!(r.bytes().as_ptr(), r.as_ptr().cast::()); + + // Assert that values written to the typed value are reflected in the + // byte slice. + const VAL1: AU64 = AU64(0xFF00FF00FF00FF00); + for typed in &mut *r { + *typed = VAL1; + } + assert_eq!(r.bytes(), VAL1.0.to_ne_bytes().repeat(typed_len).as_slice()); + + // Assert that values written to the byte slice are reflected in the + // typed value. + const VAL2: AU64 = AU64(!VAL1.0); // different from VAL1 + r.bytes_mut().copy_from_slice(&VAL2.0.to_ne_bytes().repeat(typed_len)); + assert!(r.iter().copied().all(|x| x == VAL2)); + } + + // Verify that values written to a `Ref` are properly shared between the + // typed and untyped representations, that reads via `deref` and `read` + // behave the same, and that writes via `deref_mut` and `write` behave the + // same. + fn test_new_helper_unaligned(mut r: Ref<&mut [u8], [u8; 8]>) { + // assert that the value starts at 0 + assert_eq!(*r, [0; 8]); + assert_eq!(r.read(), [0; 8]); + + // Assert that values written to the typed value are reflected in the + // byte slice. + const VAL1: [u8; 8] = [0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00]; + *r = VAL1; + assert_eq!(r.bytes(), &VAL1); + *r = [0; 8]; + r.write(VAL1); + assert_eq!(r.bytes(), &VAL1); + + // Assert that values written to the byte slice are reflected in the + // typed value. + const VAL2: [u8; 8] = [0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF]; // different from VAL1 + r.bytes_mut().copy_from_slice(&VAL2[..]); + assert_eq!(*r, VAL2); + assert_eq!(r.read(), VAL2); + } + + // Verify that values written to a `Ref` are properly shared between the + // typed and untyped representations; pass a value with `len` `u8`s backed + // by an array of `len` bytes. + fn test_new_helper_slice_unaligned(mut r: Ref<&mut [u8], [u8]>, len: usize) { + // Assert that the value starts out zeroed. + assert_eq!(&*r, vec![0u8; len].as_slice()); + + // Check the backing storage is the exact same slice. + assert_eq!(r.bytes().len(), len); + assert_eq!(r.bytes().as_ptr(), r.as_ptr()); + + // Assert that values written to the typed value are reflected in the + // byte slice. + let mut expected_bytes = [0xFF, 0x00].iter().copied().cycle().take(len).collect::>(); + r.copy_from_slice(&expected_bytes); + assert_eq!(r.bytes(), expected_bytes.as_slice()); + + // Assert that values written to the byte slice are reflected in the + // typed value. + for byte in &mut expected_bytes { + *byte = !*byte; // different from `expected_len` + } + r.bytes_mut().copy_from_slice(&expected_bytes); + assert_eq!(&*r, expected_bytes.as_slice()); + } + + #[test] + fn test_new_aligned_sized() { + // Test that a properly-aligned, properly-sized buffer works for new, + // new_from_prefix, and new_from_suffix, and that new_from_prefix and + // new_from_suffix return empty slices. Test that a properly-aligned + // buffer whose length is a multiple of the element size works for + // new_slice. Test that xxx_zeroed behaves the same, and zeroes the + // memory. + + // A buffer with an alignment of 8. + let mut buf = Align::<[u8; 8], AU64>::default(); + // `buf.t` should be aligned to 8, so this should always succeed. + test_new_helper(Ref::<_, AU64>::new(&mut buf.t[..]).unwrap()); + let ascending: [u8; 8] = (0..8).collect::>().try_into().unwrap(); + buf.t = ascending; + test_new_helper(Ref::<_, AU64>::new_zeroed(&mut buf.t[..]).unwrap()); + { + // In a block so that `r` and `suffix` don't live too long. + buf.set_default(); + let (r, suffix) = Ref::<_, AU64>::new_from_prefix(&mut buf.t[..]).unwrap(); + assert!(suffix.is_empty()); + test_new_helper(r); + } + { + buf.t = ascending; + let (r, suffix) = Ref::<_, AU64>::new_from_prefix_zeroed(&mut buf.t[..]).unwrap(); + assert!(suffix.is_empty()); + test_new_helper(r); + } + { + buf.set_default(); + let (prefix, r) = Ref::<_, AU64>::new_from_suffix(&mut buf.t[..]).unwrap(); + assert!(prefix.is_empty()); + test_new_helper(r); + } + { + buf.t = ascending; + let (prefix, r) = Ref::<_, AU64>::new_from_suffix_zeroed(&mut buf.t[..]).unwrap(); + assert!(prefix.is_empty()); + test_new_helper(r); + } + + // A buffer with alignment 8 and length 24. We choose this length very + // intentionally: if we instead used length 16, then the prefix and + // suffix lengths would be identical. In the past, we used length 16, + // which resulted in this test failing to discover the bug uncovered in + // #506. + let mut buf = Align::<[u8; 24], AU64>::default(); + // `buf.t` should be aligned to 8 and have a length which is a multiple + // of `size_of::()`, so this should always succeed. + test_new_helper_slice(Ref::<_, [AU64]>::new_slice(&mut buf.t[..]).unwrap(), 3); + let ascending: [u8; 24] = (0..24).collect::>().try_into().unwrap(); + // 16 ascending bytes followed by 8 zeros. + let mut ascending_prefix = ascending; + ascending_prefix[16..].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); + // 8 zeros followed by 16 ascending bytes. + let mut ascending_suffix = ascending; + ascending_suffix[..8].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); + test_new_helper_slice(Ref::<_, [AU64]>::new_slice_zeroed(&mut buf.t[..]).unwrap(), 3); + + { + buf.t = ascending_suffix; + let (r, suffix) = Ref::<_, [AU64]>::new_slice_from_prefix(&mut buf.t[..], 1).unwrap(); + assert_eq!(suffix, &ascending[8..]); + test_new_helper_slice(r, 1); + } + { + buf.t = ascending_suffix; + let (r, suffix) = + Ref::<_, [AU64]>::new_slice_from_prefix_zeroed(&mut buf.t[..], 1).unwrap(); + assert_eq!(suffix, &ascending[8..]); + test_new_helper_slice(r, 1); + } + { + buf.t = ascending_prefix; + let (prefix, r) = Ref::<_, [AU64]>::new_slice_from_suffix(&mut buf.t[..], 1).unwrap(); + assert_eq!(prefix, &ascending[..16]); + test_new_helper_slice(r, 1); + } + { + buf.t = ascending_prefix; + let (prefix, r) = + Ref::<_, [AU64]>::new_slice_from_suffix_zeroed(&mut buf.t[..], 1).unwrap(); + assert_eq!(prefix, &ascending[..16]); + test_new_helper_slice(r, 1); + } + } + + #[test] + fn test_new_unaligned_sized() { + // Test that an unaligned, properly-sized buffer works for + // `new_unaligned`, `new_unaligned_from_prefix`, and + // `new_unaligned_from_suffix`, and that `new_unaligned_from_prefix` + // `new_unaligned_from_suffix` return empty slices. Test that an + // unaligned buffer whose length is a multiple of the element size works + // for `new_slice`. Test that `xxx_zeroed` behaves the same, and zeroes + // the memory. + + let mut buf = [0u8; 8]; + test_new_helper_unaligned(Ref::<_, [u8; 8]>::new_unaligned(&mut buf[..]).unwrap()); + buf = [0xFFu8; 8]; + test_new_helper_unaligned(Ref::<_, [u8; 8]>::new_unaligned_zeroed(&mut buf[..]).unwrap()); + { + // In a block so that `r` and `suffix` don't live too long. + buf = [0u8; 8]; + let (r, suffix) = Ref::<_, [u8; 8]>::new_unaligned_from_prefix(&mut buf[..]).unwrap(); + assert!(suffix.is_empty()); + test_new_helper_unaligned(r); + } + { + buf = [0xFFu8; 8]; + let (r, suffix) = + Ref::<_, [u8; 8]>::new_unaligned_from_prefix_zeroed(&mut buf[..]).unwrap(); + assert!(suffix.is_empty()); + test_new_helper_unaligned(r); + } + { + buf = [0u8; 8]; + let (prefix, r) = Ref::<_, [u8; 8]>::new_unaligned_from_suffix(&mut buf[..]).unwrap(); + assert!(prefix.is_empty()); + test_new_helper_unaligned(r); + } + { + buf = [0xFFu8; 8]; + let (prefix, r) = + Ref::<_, [u8; 8]>::new_unaligned_from_suffix_zeroed(&mut buf[..]).unwrap(); + assert!(prefix.is_empty()); + test_new_helper_unaligned(r); + } + + let mut buf = [0u8; 16]; + // `buf.t` should be aligned to 8 and have a length which is a multiple + // of `size_of::AU64>()`, so this should always succeed. + test_new_helper_slice_unaligned( + Ref::<_, [u8]>::new_slice_unaligned(&mut buf[..]).unwrap(), + 16, + ); + buf = [0xFFu8; 16]; + test_new_helper_slice_unaligned( + Ref::<_, [u8]>::new_slice_unaligned_zeroed(&mut buf[..]).unwrap(), + 16, + ); + + { + buf = [0u8; 16]; + let (r, suffix) = + Ref::<_, [u8]>::new_slice_unaligned_from_prefix(&mut buf[..], 8).unwrap(); + assert_eq!(suffix, [0; 8]); + test_new_helper_slice_unaligned(r, 8); + } + { + buf = [0xFFu8; 16]; + let (r, suffix) = + Ref::<_, [u8]>::new_slice_unaligned_from_prefix_zeroed(&mut buf[..], 8).unwrap(); + assert_eq!(suffix, [0xFF; 8]); + test_new_helper_slice_unaligned(r, 8); + } + { + buf = [0u8; 16]; + let (prefix, r) = + Ref::<_, [u8]>::new_slice_unaligned_from_suffix(&mut buf[..], 8).unwrap(); + assert_eq!(prefix, [0; 8]); + test_new_helper_slice_unaligned(r, 8); + } + { + buf = [0xFFu8; 16]; + let (prefix, r) = + Ref::<_, [u8]>::new_slice_unaligned_from_suffix_zeroed(&mut buf[..], 8).unwrap(); + assert_eq!(prefix, [0xFF; 8]); + test_new_helper_slice_unaligned(r, 8); + } + } + + #[test] + fn test_new_oversized() { + // Test that a properly-aligned, overly-sized buffer works for + // `new_from_prefix` and `new_from_suffix`, and that they return the + // remainder and prefix of the slice respectively. Test that + // `xxx_zeroed` behaves the same, and zeroes the memory. + + let mut buf = Align::<[u8; 16], AU64>::default(); + { + // In a block so that `r` and `suffix` don't live too long. `buf.t` + // should be aligned to 8, so this should always succeed. + let (r, suffix) = Ref::<_, AU64>::new_from_prefix(&mut buf.t[..]).unwrap(); + assert_eq!(suffix.len(), 8); + test_new_helper(r); + } + { + buf.t = [0xFFu8; 16]; + // `buf.t` should be aligned to 8, so this should always succeed. + let (r, suffix) = Ref::<_, AU64>::new_from_prefix_zeroed(&mut buf.t[..]).unwrap(); + // Assert that the suffix wasn't zeroed. + assert_eq!(suffix, &[0xFFu8; 8]); + test_new_helper(r); + } + { + buf.set_default(); + // `buf.t` should be aligned to 8, so this should always succeed. + let (prefix, r) = Ref::<_, AU64>::new_from_suffix(&mut buf.t[..]).unwrap(); + assert_eq!(prefix.len(), 8); + test_new_helper(r); + } + { + buf.t = [0xFFu8; 16]; + // `buf.t` should be aligned to 8, so this should always succeed. + let (prefix, r) = Ref::<_, AU64>::new_from_suffix_zeroed(&mut buf.t[..]).unwrap(); + // Assert that the prefix wasn't zeroed. + assert_eq!(prefix, &[0xFFu8; 8]); + test_new_helper(r); + } + } + + #[test] + fn test_new_unaligned_oversized() { + // Test than an unaligned, overly-sized buffer works for + // `new_unaligned_from_prefix` and `new_unaligned_from_suffix`, and that + // they return the remainder and prefix of the slice respectively. Test + // that `xxx_zeroed` behaves the same, and zeroes the memory. + + let mut buf = [0u8; 16]; + { + // In a block so that `r` and `suffix` don't live too long. + let (r, suffix) = Ref::<_, [u8; 8]>::new_unaligned_from_prefix(&mut buf[..]).unwrap(); + assert_eq!(suffix.len(), 8); + test_new_helper_unaligned(r); + } + { + buf = [0xFFu8; 16]; + let (r, suffix) = + Ref::<_, [u8; 8]>::new_unaligned_from_prefix_zeroed(&mut buf[..]).unwrap(); + // Assert that the suffix wasn't zeroed. + assert_eq!(suffix, &[0xFF; 8]); + test_new_helper_unaligned(r); + } + { + buf = [0u8; 16]; + let (prefix, r) = Ref::<_, [u8; 8]>::new_unaligned_from_suffix(&mut buf[..]).unwrap(); + assert_eq!(prefix.len(), 8); + test_new_helper_unaligned(r); + } + { + buf = [0xFFu8; 16]; + let (prefix, r) = + Ref::<_, [u8; 8]>::new_unaligned_from_suffix_zeroed(&mut buf[..]).unwrap(); + // Assert that the prefix wasn't zeroed. + assert_eq!(prefix, &[0xFF; 8]); + test_new_helper_unaligned(r); + } + } + + #[test] + fn test_ref_from_mut_from() { + // Test `FromBytes::{ref_from, mut_from}{,_prefix,_suffix}` success cases + // Exhaustive coverage for these methods is covered by the `Ref` tests above, + // which these helper methods defer to. + + let mut buf = + Align::<[u8; 16], AU64>::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); + + assert_eq!( + AU64::ref_from(&buf.t[8..]).unwrap().0.to_ne_bytes(), + [8, 9, 10, 11, 12, 13, 14, 15] + ); + let suffix = AU64::mut_from(&mut buf.t[8..]).unwrap(); + suffix.0 = 0x0101010101010101; + // The `[u8:9]` is a non-half size of the full buffer, which would catch + // `from_prefix` having the same implementation as `from_suffix` (issues #506, #511). + assert_eq!(<[u8; 9]>::ref_from_suffix(&buf.t[..]).unwrap(), &[7u8, 1, 1, 1, 1, 1, 1, 1, 1]); + let suffix = AU64::mut_from_suffix(&mut buf.t[1..]).unwrap(); + suffix.0 = 0x0202020202020202; + <[u8; 10]>::mut_from_suffix(&mut buf.t[..]).unwrap()[0] = 42; + assert_eq!(<[u8; 9]>::ref_from_prefix(&buf.t[..]).unwrap(), &[0, 1, 2, 3, 4, 5, 42, 7, 2]); + <[u8; 2]>::mut_from_prefix(&mut buf.t[..]).unwrap()[1] = 30; + assert_eq!(buf.t, [0, 30, 2, 3, 4, 5, 42, 7, 2, 2, 2, 2, 2, 2, 2, 2]); + } + + #[test] + fn test_ref_from_mut_from_error() { + // Test `FromBytes::{ref_from, mut_from}{,_prefix,_suffix}` error cases. + + // Fail because the buffer is too large. + let mut buf = Align::<[u8; 16], AU64>::default(); + // `buf.t` should be aligned to 8, so only the length check should fail. + assert!(AU64::ref_from(&buf.t[..]).is_none()); + assert!(AU64::mut_from(&mut buf.t[..]).is_none()); + assert!(<[u8; 8]>::ref_from(&buf.t[..]).is_none()); + assert!(<[u8; 8]>::mut_from(&mut buf.t[..]).is_none()); + + // Fail because the buffer is too small. + let mut buf = Align::<[u8; 4], AU64>::default(); + assert!(AU64::ref_from(&buf.t[..]).is_none()); + assert!(AU64::mut_from(&mut buf.t[..]).is_none()); + assert!(<[u8; 8]>::ref_from(&buf.t[..]).is_none()); + assert!(<[u8; 8]>::mut_from(&mut buf.t[..]).is_none()); + assert!(AU64::ref_from_prefix(&buf.t[..]).is_none()); + assert!(AU64::mut_from_prefix(&mut buf.t[..]).is_none()); + assert!(AU64::ref_from_suffix(&buf.t[..]).is_none()); + assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_none()); + assert!(<[u8; 8]>::ref_from_prefix(&buf.t[..]).is_none()); + assert!(<[u8; 8]>::mut_from_prefix(&mut buf.t[..]).is_none()); + assert!(<[u8; 8]>::ref_from_suffix(&buf.t[..]).is_none()); + assert!(<[u8; 8]>::mut_from_suffix(&mut buf.t[..]).is_none()); + + // Fail because the alignment is insufficient. + let mut buf = Align::<[u8; 13], AU64>::default(); + assert!(AU64::ref_from(&buf.t[1..]).is_none()); + assert!(AU64::mut_from(&mut buf.t[1..]).is_none()); + assert!(AU64::ref_from(&buf.t[1..]).is_none()); + assert!(AU64::mut_from(&mut buf.t[1..]).is_none()); + assert!(AU64::ref_from_prefix(&buf.t[1..]).is_none()); + assert!(AU64::mut_from_prefix(&mut buf.t[1..]).is_none()); + assert!(AU64::ref_from_suffix(&buf.t[..]).is_none()); + assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_none()); + } + + #[test] + #[allow(clippy::cognitive_complexity)] + fn test_new_error() { + // Fail because the buffer is too large. + + // A buffer with an alignment of 8. + let mut buf = Align::<[u8; 16], AU64>::default(); + // `buf.t` should be aligned to 8, so only the length check should fail. + assert!(Ref::<_, AU64>::new(&buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned(&buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned_zeroed(&mut buf.t[..]).is_none()); + + // Fail because the buffer is too small. + + // A buffer with an alignment of 8. + let mut buf = Align::<[u8; 4], AU64>::default(); + // `buf.t` should be aligned to 8, so only the length check should fail. + assert!(Ref::<_, AU64>::new(&buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned(&buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_from_prefix(&buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_from_prefix_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_from_suffix(&buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_from_suffix_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned_from_prefix(&buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned_from_prefix_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned_from_suffix(&buf.t[..]).is_none()); + assert!(Ref::<_, [u8; 8]>::new_unaligned_from_suffix_zeroed(&mut buf.t[..]).is_none()); + + // Fail because the length is not a multiple of the element size. + + let mut buf = Align::<[u8; 12], AU64>::default(); + // `buf.t` has length 12, but element size is 8. + assert!(Ref::<_, [AU64]>::new_slice(&buf.t[..]).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_zeroed(&mut buf.t[..]).is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned(&buf.t[..]).is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_zeroed(&mut buf.t[..]).is_none()); + + // Fail because the buffer is too short. + let mut buf = Align::<[u8; 12], AU64>::default(); + // `buf.t` has length 12, but the element size is 8 (and we're expecting + // two of them). + assert!(Ref::<_, [AU64]>::new_slice_from_prefix(&buf.t[..], 2).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_prefix_zeroed(&mut buf.t[..], 2).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_suffix(&buf.t[..], 2).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_suffix_zeroed(&mut buf.t[..], 2).is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_prefix(&buf.t[..], 2).is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_prefix_zeroed(&mut buf.t[..], 2) + .is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_suffix(&buf.t[..], 2).is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_suffix_zeroed(&mut buf.t[..], 2) + .is_none()); + + // Fail because the alignment is insufficient. + + // A buffer with an alignment of 8. An odd buffer size is chosen so that + // the last byte of the buffer has odd alignment. + let mut buf = Align::<[u8; 13], AU64>::default(); + // Slicing from 1, we get a buffer with size 12 (so the length check + // should succeed) but an alignment of only 1, which is insufficient. + assert!(Ref::<_, AU64>::new(&buf.t[1..]).is_none()); + assert!(Ref::<_, AU64>::new_zeroed(&mut buf.t[1..]).is_none()); + assert!(Ref::<_, AU64>::new_from_prefix(&buf.t[1..]).is_none()); + assert!(Ref::<_, AU64>::new_from_prefix_zeroed(&mut buf.t[1..]).is_none()); + assert!(Ref::<_, [AU64]>::new_slice(&buf.t[1..]).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_zeroed(&mut buf.t[1..]).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_prefix(&buf.t[1..], 1).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_prefix_zeroed(&mut buf.t[1..], 1).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_suffix(&buf.t[1..], 1).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_suffix_zeroed(&mut buf.t[1..], 1).is_none()); + // Slicing is unnecessary here because `new_from_suffix[_zeroed]` use + // the suffix of the slice, which has odd alignment. + assert!(Ref::<_, AU64>::new_from_suffix(&buf.t[..]).is_none()); + assert!(Ref::<_, AU64>::new_from_suffix_zeroed(&mut buf.t[..]).is_none()); + + // Fail due to arithmetic overflow. + + let mut buf = Align::<[u8; 16], AU64>::default(); + let unreasonable_len = usize::MAX / mem::size_of::() + 1; + assert!(Ref::<_, [AU64]>::new_slice_from_prefix(&buf.t[..], unreasonable_len).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_prefix_zeroed(&mut buf.t[..], unreasonable_len) + .is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_suffix(&buf.t[..], unreasonable_len).is_none()); + assert!(Ref::<_, [AU64]>::new_slice_from_suffix_zeroed(&mut buf.t[..], unreasonable_len) + .is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_prefix(&buf.t[..], unreasonable_len) + .is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_prefix_zeroed( + &mut buf.t[..], + unreasonable_len + ) + .is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_suffix(&buf.t[..], unreasonable_len) + .is_none()); + assert!(Ref::<_, [[u8; 8]]>::new_slice_unaligned_from_suffix_zeroed( + &mut buf.t[..], + unreasonable_len + ) + .is_none()); + } + + // Tests for ensuring that, if a ZST is passed into a slice-like function, + // we always panic. Since these tests need to be separate per-function, and + // they tend to take up a lot of space, we generate them using a macro in a + // submodule instead. The submodule ensures that we can just re-use the name + // of the function under test for the name of the test itself. + mod test_zst_panics { + macro_rules! zst_test { + ($name:ident($($tt:tt)*), $constructor_in_panic_msg:tt) => { + #[test] + #[should_panic = concat!("Ref::", $constructor_in_panic_msg, " called on a zero-sized type")] + fn $name() { + let mut buffer = [0u8]; + let r = $crate::Ref::<_, [()]>::$name(&mut buffer[..], $($tt)*); + unreachable!("should have panicked, got {:?}", r); + } + } + } + zst_test!(new_slice(), "new_slice"); + zst_test!(new_slice_zeroed(), "new_slice"); + zst_test!(new_slice_from_prefix(1), "new_slice"); + zst_test!(new_slice_from_prefix_zeroed(1), "new_slice"); + zst_test!(new_slice_from_suffix(1), "new_slice"); + zst_test!(new_slice_from_suffix_zeroed(1), "new_slice"); + zst_test!(new_slice_unaligned(), "new_slice_unaligned"); + zst_test!(new_slice_unaligned_zeroed(), "new_slice_unaligned"); + zst_test!(new_slice_unaligned_from_prefix(1), "new_slice_unaligned"); + zst_test!(new_slice_unaligned_from_prefix_zeroed(1), "new_slice_unaligned"); + zst_test!(new_slice_unaligned_from_suffix(1), "new_slice_unaligned"); + zst_test!(new_slice_unaligned_from_suffix_zeroed(1), "new_slice_unaligned"); + } + + #[test] + fn test_as_bytes_methods() { + /// Run a series of tests by calling `AsBytes` methods on `t`. + /// + /// `bytes` is the expected byte sequence returned from `t.as_bytes()` + /// before `t` has been modified. `post_mutation` is the expected + /// sequence returned from `t.as_bytes()` after `t.as_bytes_mut()[0]` + /// has had its bits flipped (by applying `^= 0xFF`). + /// + /// `N` is the size of `t` in bytes. + fn test( + t: &mut T, + bytes: &[u8], + post_mutation: &T, + ) { + // Test that we can access the underlying bytes, and that we get the + // right bytes and the right number of bytes. + assert_eq!(t.as_bytes(), bytes); + + // Test that changes to the underlying byte slices are reflected in + // the original object. + t.as_bytes_mut()[0] ^= 0xFF; + assert_eq!(t, post_mutation); + t.as_bytes_mut()[0] ^= 0xFF; + + // `write_to` rejects slices that are too small or too large. + assert_eq!(t.write_to(&mut vec![0; N - 1][..]), None); + assert_eq!(t.write_to(&mut vec![0; N + 1][..]), None); + + // `write_to` works as expected. + let mut bytes = [0; N]; + assert_eq!(t.write_to(&mut bytes[..]), Some(())); + assert_eq!(bytes, t.as_bytes()); + + // `write_to_prefix` rejects slices that are too small. + assert_eq!(t.write_to_prefix(&mut vec![0; N - 1][..]), None); + + // `write_to_prefix` works with exact-sized slices. + let mut bytes = [0; N]; + assert_eq!(t.write_to_prefix(&mut bytes[..]), Some(())); + assert_eq!(bytes, t.as_bytes()); + + // `write_to_prefix` works with too-large slices, and any bytes past + // the prefix aren't modified. + let mut too_many_bytes = vec![0; N + 1]; + too_many_bytes[N] = 123; + assert_eq!(t.write_to_prefix(&mut too_many_bytes[..]), Some(())); + assert_eq!(&too_many_bytes[..N], t.as_bytes()); + assert_eq!(too_many_bytes[N], 123); + + // `write_to_suffix` rejects slices that are too small. + assert_eq!(t.write_to_suffix(&mut vec![0; N - 1][..]), None); + + // `write_to_suffix` works with exact-sized slices. + let mut bytes = [0; N]; + assert_eq!(t.write_to_suffix(&mut bytes[..]), Some(())); + assert_eq!(bytes, t.as_bytes()); + + // `write_to_suffix` works with too-large slices, and any bytes + // before the suffix aren't modified. + let mut too_many_bytes = vec![0; N + 1]; + too_many_bytes[0] = 123; + assert_eq!(t.write_to_suffix(&mut too_many_bytes[..]), Some(())); + assert_eq!(&too_many_bytes[1..], t.as_bytes()); + assert_eq!(too_many_bytes[0], 123); + } + + #[derive(Debug, Eq, PartialEq, FromZeroes, FromBytes, AsBytes)] + #[repr(C)] + struct Foo { + a: u32, + b: Wrapping, + c: Option, + } + + let expected_bytes: Vec = if cfg!(target_endian = "little") { + vec![1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0] + } else { + vec![0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0] + }; + let post_mutation_expected_a = + if cfg!(target_endian = "little") { 0x00_00_00_FE } else { 0xFF_00_00_01 }; + test::<_, 12>( + &mut Foo { a: 1, b: Wrapping(2), c: None }, + expected_bytes.as_bytes(), + &Foo { a: post_mutation_expected_a, b: Wrapping(2), c: None }, + ); + test::<_, 3>( + Unsized::from_mut_slice(&mut [1, 2, 3]), + &[1, 2, 3], + Unsized::from_mut_slice(&mut [0xFE, 2, 3]), + ); + } + + #[test] + fn test_array() { + #[derive(FromZeroes, FromBytes, AsBytes)] + #[repr(C)] + struct Foo { + a: [u16; 33], + } + + let foo = Foo { a: [0xFFFF; 33] }; + let expected = [0xFFu8; 66]; + assert_eq!(foo.as_bytes(), &expected[..]); + } + + #[test] + fn test_display_debug() { + let buf = Align::<[u8; 8], u64>::default(); + let r = Ref::<_, u64>::new(&buf.t[..]).unwrap(); + assert_eq!(format!("{}", r), "0"); + assert_eq!(format!("{:?}", r), "Ref(0)"); + + let buf = Align::<[u8; 8], u64>::default(); + let r = Ref::<_, [u64]>::new_slice(&buf.t[..]).unwrap(); + assert_eq!(format!("{:?}", r), "Ref([0])"); + } + + #[test] + fn test_eq() { + let buf1 = 0_u64; + let r1 = Ref::<_, u64>::new(buf1.as_bytes()).unwrap(); + let buf2 = 0_u64; + let r2 = Ref::<_, u64>::new(buf2.as_bytes()).unwrap(); + assert_eq!(r1, r2); + } + + #[test] + fn test_ne() { + let buf1 = 0_u64; + let r1 = Ref::<_, u64>::new(buf1.as_bytes()).unwrap(); + let buf2 = 1_u64; + let r2 = Ref::<_, u64>::new(buf2.as_bytes()).unwrap(); + assert_ne!(r1, r2); + } + + #[test] + fn test_ord() { + let buf1 = 0_u64; + let r1 = Ref::<_, u64>::new(buf1.as_bytes()).unwrap(); + let buf2 = 1_u64; + let r2 = Ref::<_, u64>::new(buf2.as_bytes()).unwrap(); + assert!(r1 < r2); + } + + #[test] + fn test_new_zeroed() { + assert!(!bool::new_zeroed()); + assert_eq!(u64::new_zeroed(), 0); + // This test exists in order to exercise unsafe code, especially when + // running under Miri. + #[allow(clippy::unit_cmp)] + { + assert_eq!(<()>::new_zeroed(), ()); + } + } + + #[test] + fn test_transparent_packed_generic_struct() { + #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + #[repr(transparent)] + struct Foo { + _t: T, + _phantom: PhantomData<()>, + } + + assert_impl_all!(Foo: FromZeroes, FromBytes, AsBytes); + assert_impl_all!(Foo: Unaligned); + + #[derive(AsBytes, FromZeroes, FromBytes, Unaligned)] + #[repr(packed)] + struct Bar { + _t: T, + _u: U, + } + + assert_impl_all!(Bar: FromZeroes, FromBytes, AsBytes, Unaligned); + } + + #[test] + fn test_impls() { + use core::borrow::Borrow; + + // A type that can supply test cases for testing + // `TryFromBytes::is_bit_valid`. All types passed to `assert_impls!` + // must implement this trait; that macro uses it to generate runtime + // tests for `TryFromBytes` impls. + // + // All `T: FromBytes` types are provided with a blanket impl. Other + // types must implement `TryFromBytesTestable` directly (ie using + // `impl_try_from_bytes_testable!`). + trait TryFromBytesTestable { + fn with_passing_test_cases(f: F); + fn with_failing_test_cases(f: F); + } + + impl TryFromBytesTestable for T { + fn with_passing_test_cases(f: F) { + // Test with a zeroed value. + f(&Self::new_zeroed()); + + let ffs = { + let mut t = Self::new_zeroed(); + let ptr: *mut T = &mut t; + // SAFETY: `T: FromBytes` + unsafe { ptr::write_bytes(ptr.cast::(), 0xFF, mem::size_of::()) }; + t + }; + + // Test with a value initialized with 0xFF. + f(&ffs); + } + + fn with_failing_test_cases(_f: F) {} + } + + // Implements `TryFromBytesTestable`. + macro_rules! impl_try_from_bytes_testable { + // Base case for recursion (when the list of types has run out). + (=> @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => {}; + // Implements for type(s) with no type parameters. + ($ty:ty $(,$tys:ty)* => @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => { + impl TryFromBytesTestable for $ty { + impl_try_from_bytes_testable!( + @methods @success $($success_case),* + $(, @failure $($failure_case),*)? + ); + } + impl_try_from_bytes_testable!($($tys),* => @success $($success_case),* $(, @failure $($failure_case),*)?); + }; + // Implements for multiple types with no type parameters. + ($($($ty:ty),* => @success $($success_case:expr), * $(, @failure $($failure_case:expr),*)?;)*) => { + $( + impl_try_from_bytes_testable!($($ty),* => @success $($success_case),* $(, @failure $($failure_case),*)*); + )* + }; + // Implements only the methods; caller must invoke this from inside + // an impl block. + (@methods @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => { + fn with_passing_test_cases(_f: F) { + $( + _f($success_case.borrow()); + )* + } + + fn with_failing_test_cases(_f: F) { + $($( + // `unused_qualifications` is spuriously triggered on + // `Option::::None`. + #[allow(unused_qualifications)] + let case = $failure_case.as_bytes(); + _f(case.as_bytes()); + )*)? + } + }; + } + + // Note that these impls are only for types which are not `FromBytes`. + // `FromBytes` types are covered by a preceding blanket impl. + impl_try_from_bytes_testable!( + bool => @success true, false, + @failure 2u8, 3u8, 0xFFu8; + char => @success '\u{0}', '\u{D7FF}', '\u{E000}', '\u{10FFFF}', + @failure 0xD800u32, 0xDFFFu32, 0x110000u32; + str => @success "", "hello", "โค๏ธ๐Ÿงก๐Ÿ’›๐Ÿ’š๐Ÿ’™๐Ÿ’œ", + @failure [0, 159, 146, 150]; + [u8] => @success [], [0, 1, 2]; + NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, + NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, + NonZeroUsize, NonZeroIsize + => @success Self::new(1).unwrap(), + // Doing this instead of `0` ensures that we always satisfy + // the size and alignment requirements of `Self` (whereas + // `0` may be any integer type with a different size or + // alignment than some `NonZeroXxx` types). + @failure Option::::None; + [bool] + => @success [true, false], [false, true], + @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8]; + ); + + // Asserts that `$ty` implements any `$trait` and doesn't implement any + // `!$trait`. Note that all `$trait`s must come before any `!$trait`s. + // + // For `T: TryFromBytes`, uses `TryFromBytesTestable` to test success + // and failure cases for `TryFromBytes::is_bit_valid`. + macro_rules! assert_impls { + ($ty:ty: TryFromBytes) => { + <$ty as TryFromBytesTestable>::with_passing_test_cases(|val| { + let c = Ptr::from(val); + // SAFETY: + // - Since `val` is a normal reference, `c` is guranteed to + // be aligned, to point to a single allocation, and to + // have a size which doesn't overflow `isize`. + // - Since `val` is a valid `$ty`, `c`'s referent satisfies + // the bit validity constraints of `is_bit_valid`, which + // are a superset of the bit validity constraints of + // `$ty`. + let res = unsafe { <$ty as TryFromBytes>::is_bit_valid(c) }; + assert!(res, "{}::is_bit_valid({:?}): got false, expected true", stringify!($ty), val); + + // TODO(#5): In addition to testing `is_bit_valid`, test the + // methods built on top of it. This would both allow us to + // test their implementations and actually convert the bytes + // to `$ty`, giving Miri a chance to catch if this is + // unsound (ie, if our `is_bit_valid` impl is buggy). + // + // The following code was tried, but it doesn't work because + // a) some types are not `AsBytes` and, b) some types are + // not `Sized`. + // + // let r = <$ty as TryFromBytes>::try_from_ref(val.as_bytes()).unwrap(); + // assert_eq!(r, &val); + // let r = <$ty as TryFromBytes>::try_from_mut(val.as_bytes_mut()).unwrap(); + // assert_eq!(r, &mut val); + // let v = <$ty as TryFromBytes>::try_read_from(val.as_bytes()).unwrap(); + // assert_eq!(v, val); + }); + #[allow(clippy::as_conversions)] + <$ty as TryFromBytesTestable>::with_failing_test_cases(|c| { + let res = <$ty as TryFromBytes>::try_from_ref(c); + assert!(res.is_none(), "{}::is_bit_valid({:?}): got true, expected false", stringify!($ty), c); + }); + + #[allow(dead_code)] + const _: () = { static_assertions::assert_impl_all!($ty: TryFromBytes); }; + }; + ($ty:ty: $trait:ident) => { + #[allow(dead_code)] + const _: () = { static_assertions::assert_impl_all!($ty: $trait); }; + }; + ($ty:ty: !$trait:ident) => { + #[allow(dead_code)] + const _: () = { static_assertions::assert_not_impl_any!($ty: $trait); }; + }; + ($ty:ty: $($trait:ident),* $(,)? $(!$negative_trait:ident),*) => { + $( + assert_impls!($ty: $trait); + )* + + $( + assert_impls!($ty: !$negative_trait); + )* + }; + } + + // NOTE: The negative impl assertions here are not necessarily + // prescriptive. They merely serve as change detectors to make sure + // we're aware of what trait impls are getting added with a given + // change. Of course, some impls would be invalid (e.g., `bool: + // FromBytes`), and so this change detection is very important. + + assert_impls!((): KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(u8: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(i8: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(u16: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(i16: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(u32: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(i32: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(u64: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(i64: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(u128: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(i128: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(usize: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(isize: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(f32: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(f64: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + + assert_impls!(bool: KnownLayout, TryFromBytes, FromZeroes, AsBytes, Unaligned, !FromBytes); + assert_impls!(char: KnownLayout, TryFromBytes, FromZeroes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(str: KnownLayout, TryFromBytes, FromZeroes, AsBytes, Unaligned, !FromBytes); + + assert_impls!(NonZeroU8: KnownLayout, TryFromBytes, AsBytes, Unaligned, !FromZeroes, !FromBytes); + assert_impls!(NonZeroI8: KnownLayout, TryFromBytes, AsBytes, Unaligned, !FromZeroes, !FromBytes); + assert_impls!(NonZeroU16: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroI16: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroU32: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroI32: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroU64: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroI64: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroU128: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroI128: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroUsize: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + assert_impls!(NonZeroIsize: KnownLayout, TryFromBytes, AsBytes, !FromBytes, !Unaligned); + + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); + + // Implements none of the ZC traits. + struct NotZerocopy; + + #[rustfmt::skip] + type FnManyArgs = fn( + NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, + ) -> (NotZerocopy, NotZerocopy); + + // Allowed, because we're not actually using this type for FFI. + #[allow(improper_ctypes_definitions)] + #[rustfmt::skip] + type ECFnManyArgs = extern "C" fn( + NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, + ) -> (NotZerocopy, NotZerocopy); + + #[cfg(feature = "alloc")] + assert_impls!(Option>>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option]>>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option<&'static UnsafeCell>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option<&'static [UnsafeCell]>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option<&'static mut UnsafeCell>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option<&'static mut [UnsafeCell]>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option>>: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option]>>: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + + assert_impls!(PhantomData: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(PhantomData<[u8]>: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + + assert_impls!(ManuallyDrop: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes); + assert_impls!(ManuallyDrop<[u8]>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes); + assert_impls!(ManuallyDrop: !TryFromBytes, !KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(ManuallyDrop<[NotZerocopy]>: !TryFromBytes, !KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + + assert_impls!(MaybeUninit: KnownLayout, TryFromBytes, FromZeroes, FromBytes, Unaligned, !AsBytes); + assert_impls!(MaybeUninit: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + + assert_impls!(Wrapping: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!(Wrapping: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + + assert_impls!(Unalign: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes); + assert_impls!(Unalign: Unaligned, !KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes); + + assert_impls!([u8]: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned); + assert_impls!([bool]: KnownLayout, TryFromBytes, FromZeroes, AsBytes, Unaligned, !FromBytes); + assert_impls!([NotZerocopy]: !KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!([u8; 0]: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes); + assert_impls!([NotZerocopy; 0]: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!([u8; 1]: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes); + assert_impls!([NotZerocopy; 1]: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + + assert_impls!(*const NotZerocopy: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(*mut NotZerocopy: KnownLayout, FromZeroes, !TryFromBytes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(*const [NotZerocopy]: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(*mut [NotZerocopy]: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(*const dyn Debug: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(*mut dyn Debug: KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + + #[cfg(feature = "simd")] + { + #[allow(unused_macros)] + macro_rules! test_simd_arch_mod { + ($arch:ident, $($typ:ident),*) => { + { + use core::arch::$arch::{$($typ),*}; + use crate::*; + $( assert_impls!($typ: KnownLayout, TryFromBytes, FromZeroes, FromBytes, AsBytes, !Unaligned); )* + } + }; + } + #[cfg(target_arch = "x86")] + test_simd_arch_mod!(x86, __m128, __m128d, __m128i, __m256, __m256d, __m256i); + + #[cfg(all(feature = "simd-nightly", target_arch = "x86"))] + test_simd_arch_mod!(x86, __m512bh, __m512, __m512d, __m512i); + + #[cfg(target_arch = "x86_64")] + test_simd_arch_mod!(x86_64, __m128, __m128d, __m128i, __m256, __m256d, __m256i); + + #[cfg(all(feature = "simd-nightly", target_arch = "x86_64"))] + test_simd_arch_mod!(x86_64, __m512bh, __m512, __m512d, __m512i); + + #[cfg(target_arch = "wasm32")] + test_simd_arch_mod!(wasm32, v128); + + #[cfg(all(feature = "simd-nightly", target_arch = "powerpc"))] + test_simd_arch_mod!( + powerpc, + vector_bool_long, + vector_double, + vector_signed_long, + vector_unsigned_long + ); + + #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))] + test_simd_arch_mod!( + powerpc64, + vector_bool_long, + vector_double, + vector_signed_long, + vector_unsigned_long + ); + #[cfg(target_arch = "aarch64")] + #[rustfmt::skip] + test_simd_arch_mod!( + aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t, + int8x8x3_t, int8x8x4_t, int8x16_t, int8x16x2_t, int8x16x3_t, int8x16x4_t, int16x4_t, + int16x8_t, int32x2_t, int32x4_t, int64x1_t, int64x2_t, poly8x8_t, poly8x8x2_t, poly8x8x3_t, + poly8x8x4_t, poly8x16_t, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t, poly16x4_t, poly16x8_t, + poly64x1_t, poly64x2_t, uint8x8_t, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t, uint8x16_t, + uint8x16x2_t, uint8x16x3_t, uint8x16x4_t, uint16x4_t, uint16x8_t, uint32x2_t, uint32x4_t, + uint64x1_t, uint64x2_t + ); + #[cfg(all(feature = "simd-nightly", target_arch = "arm"))] + #[rustfmt::skip] + test_simd_arch_mod!(arm, int8x4_t, uint8x4_t); + } + } +} + +#[cfg(kani)] +mod proofs { + use super::*; + + impl kani::Arbitrary for DstLayout { + fn any() -> Self { + let align: NonZeroUsize = kani::any(); + let size_info: SizeInfo = kani::any(); + + kani::assume(align.is_power_of_two()); + kani::assume(align < DstLayout::THEORETICAL_MAX_ALIGN); + + // For testing purposes, we most care about instantiations of + // `DstLayout` that can correspond to actual Rust types. We use + // `Layout` to verify that our `DstLayout` satisfies the validity + // conditions of Rust layouts. + kani::assume( + match size_info { + SizeInfo::Sized { _size } => Layout::from_size_align(_size, align.get()), + SizeInfo::SliceDst(TrailingSliceLayout { _offset, _elem_size }) => { + // `SliceDst`` cannot encode an exact size, but we know + // it is at least `_offset` bytes. + Layout::from_size_align(_offset, align.get()) + } + } + .is_ok(), + ); + + Self { align: align, size_info: size_info } + } + } + + impl kani::Arbitrary for SizeInfo { + fn any() -> Self { + let is_sized: bool = kani::any(); + + match is_sized { + true => { + let size: usize = kani::any(); + + kani::assume(size <= isize::MAX as _); + + SizeInfo::Sized { _size: size } + } + false => SizeInfo::SliceDst(kani::any()), + } + } + } + + impl kani::Arbitrary for TrailingSliceLayout { + fn any() -> Self { + let elem_size: usize = kani::any(); + let offset: usize = kani::any(); + + kani::assume(elem_size < isize::MAX as _); + kani::assume(offset < isize::MAX as _); + + TrailingSliceLayout { _elem_size: elem_size, _offset: offset } + } + } + + #[kani::proof] + fn prove_dst_layout_extend() { + use crate::util::{core_layout::padding_needed_for, max, min}; + + let base: DstLayout = kani::any(); + let field: DstLayout = kani::any(); + let packed: Option = kani::any(); + + if let Some(max_align) = packed { + kani::assume(max_align.is_power_of_two()); + kani::assume(base.align <= max_align); + } + + // The base can only be extended if it's sized. + kani::assume(matches!(base.size_info, SizeInfo::Sized { .. })); + let base_size = if let SizeInfo::Sized { _size: size } = base.size_info { + size + } else { + unreachable!(); + }; + + // Under the above conditions, `DstLayout::extend` will not panic. + let composite = base.extend(field, packed); + + // The field's alignment is clamped by `max_align` (i.e., the + // `packed` attribute, if any) [1]. + // + // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers: + // + // The alignments of each field, for the purpose of positioning + // fields, is the smaller of the specified alignment and the + // alignment of the field's type. + let field_align = min(field.align, packed.unwrap_or(DstLayout::THEORETICAL_MAX_ALIGN)); + + // The struct's alignment is the maximum of its previous alignment and + // `field_align`. + assert_eq!(composite.align, max(base.align, field_align)); + + // Compute the minimum amount of inter-field padding needed to + // satisfy the field's alignment, and offset of the trailing field. + // [1] + // + // [1] Per https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers: + // + // Inter-field padding is guaranteed to be the minimum required in + // order to satisfy each field's (possibly altered) alignment. + let padding = padding_needed_for(base_size, field_align); + let offset = base_size + padding; + + // For testing purposes, we'll also construct `alloc::Layout` + // stand-ins for `DstLayout`, and show that `extend` behaves + // comparably on both types. + let base_analog = Layout::from_size_align(base_size, base.align.get()).unwrap(); + + match field.size_info { + SizeInfo::Sized { _size: field_size } => { + if let SizeInfo::Sized { _size: composite_size } = composite.size_info { + // If the trailing field is sized, the resulting layout + // will be sized. Its size will be the sum of the + // preceeding layout, the size of the new field, and the + // size of inter-field padding between the two. + assert_eq!(composite_size, offset + field_size); + + let field_analog = + Layout::from_size_align(field_size, field_align.get()).unwrap(); + + if let Ok((actual_composite, actual_offset)) = base_analog.extend(field_analog) + { + assert_eq!(actual_offset, offset); + assert_eq!(actual_composite.size(), composite_size); + assert_eq!(actual_composite.align(), composite.align.get()); + } else { + // An error here reflects that composite of `base` + // and `field` cannot correspond to a real Rust type + // fragment, because such a fragment would violate + // the basic invariants of a valid Rust layout. At + // the time of writing, `DstLayout` is a little more + // permissive than `Layout`, so we don't assert + // anything in this branch (e.g., unreachability). + } + } else { + panic!("The composite of two sized layouts must be sized.") + } + } + SizeInfo::SliceDst(TrailingSliceLayout { + _offset: field_offset, + _elem_size: field_elem_size, + }) => { + if let SizeInfo::SliceDst(TrailingSliceLayout { + _offset: composite_offset, + _elem_size: composite_elem_size, + }) = composite.size_info + { + // The offset of the trailing slice component is the sum + // of the offset of the trailing field and the trailing + // slice offset within that field. + assert_eq!(composite_offset, offset + field_offset); + // The elem size is unchanged. + assert_eq!(composite_elem_size, field_elem_size); + + let field_analog = + Layout::from_size_align(field_offset, field_align.get()).unwrap(); + + if let Ok((actual_composite, actual_offset)) = base_analog.extend(field_analog) + { + assert_eq!(actual_offset, offset); + assert_eq!(actual_composite.size(), composite_offset); + assert_eq!(actual_composite.align(), composite.align.get()); + } else { + // An error here reflects that composite of `base` + // and `field` cannot correspond to a real Rust type + // fragment, because such a fragment would violate + // the basic invariants of a valid Rust layout. At + // the time of writing, `DstLayout` is a little more + // permissive than `Layout`, so we don't assert + // anything in this branch (e.g., unreachability). + } + } else { + panic!("The extension of a layout with a DST must result in a DST.") + } + } + } + } + + #[kani::proof] + #[kani::should_panic] + fn prove_dst_layout_extend_dst_panics() { + let base: DstLayout = kani::any(); + let field: DstLayout = kani::any(); + let packed: Option = kani::any(); + + if let Some(max_align) = packed { + kani::assume(max_align.is_power_of_two()); + kani::assume(base.align <= max_align); + } + + kani::assume(matches!(base.size_info, SizeInfo::SliceDst(..))); + + let _ = base.extend(field, packed); + } + + #[kani::proof] + fn prove_dst_layout_pad_to_align() { + use crate::util::core_layout::padding_needed_for; + + let layout: DstLayout = kani::any(); + + let padded: DstLayout = layout.pad_to_align(); + + // Calling `pad_to_align` does not alter the `DstLayout`'s alignment. + assert_eq!(padded.align, layout.align); + + if let SizeInfo::Sized { _size: unpadded_size } = layout.size_info { + if let SizeInfo::Sized { _size: padded_size } = padded.size_info { + // If the layout is sized, it will remain sized after padding is + // added. Its sum will be its unpadded size and the size of the + // trailing padding needed to satisfy its alignment + // requirements. + let padding = padding_needed_for(unpadded_size, layout.align); + assert_eq!(padded_size, unpadded_size + padding); + + // Prove that calling `DstLayout::pad_to_align` behaves + // identically to `Layout::pad_to_align`. + let layout_analog = + Layout::from_size_align(unpadded_size, layout.align.get()).unwrap(); + let padded_analog = layout_analog.pad_to_align(); + assert_eq!(padded_analog.align(), layout.align.get()); + assert_eq!(padded_analog.size(), padded_size); + } else { + panic!("The padding of a sized layout must result in a sized layout.") + } + } else { + // If the layout is a DST, padding cannot be statically added. + assert_eq!(padded.size_info, layout.size_info); + } + } +} -- cgit v1.2.3