// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT//// Copyright 2024 The Fuchsia Authors//// Licensed under the 2-Clause BSD License <LICENSE-BSD or// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.// This file may not be copied, modified, or distributed except according to// those terms. use core::{ cell::{Cell, UnsafeCell}, mem::MaybeUninit as CoreMaybeUninit, ptr::NonNull,}; use super::*;use crate::pointer::cast::{CastSizedExact, CastUnsized}; // 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."// - `Immutable`: `()` self-evidently does not contain any `UnsafeCell`s.// - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: There is only// one possible sequence of 0 bytes, and `()` is inhabited.// - `IntoBytes`: Since `()` has size 0, it contains no padding bytes.// - `Unaligned`: `()` has alignment 1.//// [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#tuple-layout#[allow(clippy::multiple_unsafe_ops_per_block)]const _: () = unsafe { unsafe_impl!((): Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_unaligned!(());}; // SAFETY:// - `Immutable`: These types self-evidently do not contain any `UnsafeCell`s.// - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: all bit// patterns are valid for numeric types [1]// - `IntoBytes`: 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/1.81.0/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::<T>()]`. An uninitialized byte is// not a valid `u8`.//// [2] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#primitive-data-layout//// [3] Per https://doc.rust-lang.org/1.81.0/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/1.81.0/reference/type-layout.html#size-and-alignment://// The size of a value is always a multiple of its alignment.//// FIXME(#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].#[allow(clippy::multiple_unsafe_ops_per_block)]const _: () = unsafe { unsafe_impl!(u8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); unsafe_impl!(i8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_unaligned!(u8, i8); unsafe_impl!(u16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(i16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(u32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(i32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(u64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(i64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(u128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(i128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(usize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(isize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(f32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(f64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); #[cfg(feature = "float-nightly")] unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); #[cfg(feature = "float-nightly")] unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);}; // SAFETY:// - `Immutable`: `bool` self-evidently does not contain any `UnsafeCell`s.// - `FromZeros`: Valid since "[t]he value false has the bit pattern 0x00" [1].// - `IntoBytes`: 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/1.81.0/reference/types/boolean.html#[allow(clippy::multiple_unsafe_ops_per_block)]const _: () = unsafe { unsafe_impl!(bool: Immutable, FromZeros, IntoBytes, Unaligned) };assert_unaligned!(bool); // SAFETY: The impl must only return `true` for its argument if the original// `Maybe<bool>` 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` [1].//// [1] Per https://doc.rust-lang.org/1.81.0/reference/types/boolean.html://// The value false has the bit pattern 0x00 and the value true has the bit// pattern 0x01.const _: () = unsafe { unsafe_impl!(=> TryFromBytes for bool; |byte| { let byte = byte.transmute_with::<u8, invariant::Valid, CastSizedExact, BecauseImmutable>(); *byte.unaligned_as_ref() < 2 })}; // SAFETY:// - `Immutable`: `char` self-evidently does not contain any `UnsafeCell`s.// - `FromZeros`: 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.// - `IntoBytes`: `char` is per reference [1] "represented as a 32-bit unsigned// word" (`u32`) which is `IntoBytes`. Note that unlike `u32`, not all bit// patterns are valid for `char`.//// [1] https://doc.rust-lang.org/1.81.0/reference/types/textual.html#[allow(clippy::multiple_unsafe_ops_per_block)]const _: () = unsafe { unsafe_impl!(char: Immutable, FromZeros, IntoBytes) }; // SAFETY: The impl must only return `true` for its argument if the original// `Maybe<char>` refers to a valid `char`. `char::from_u32` guarantees that it// returns `None` if its input is not a valid `char` [1].//// [1] 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`.const _: () = unsafe { unsafe_impl!(=> TryFromBytes for char; |c| { let c = c.transmute_with::<Unalign<u32>, invariant::Valid, CastSizedExact, BecauseImmutable>(); let c = c.read().into_inner(); char::from_u32(c).is_some() });}; // SAFETY: Per the Reference [1], `str` has the same layout as `[u8]`.// - `Immutable`: `[u8]` does not contain any `UnsafeCell`s.// - `FromZeros`, `IntoBytes`, `Unaligned`: `[u8]` is `FromZeros`, `IntoBytes`,// and `Unaligned`.//// Note that we don't `assert_unaligned!(str)` because `assert_unaligned!` uses// `align_of`, which only works for `Sized` types.//// FIXME(#429): Improve safety proof for `FromZeros` and `IntoBytes`; having the same// layout as `[u8]` isn't sufficient.//// [1] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#str-layout://// String slices are a UTF-8 representation of characters that have the same// layout as slices of type `[u8]`.#[allow(clippy::multiple_unsafe_ops_per_block)]const _: () = unsafe { unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unaligned) }; // SAFETY: The impl must only return `true` for its argument if the original// `Maybe<str>` refers to a valid `str`. `str::from_utf8` guarantees that it// returns `Err` if its input is not a valid `str` [1].//// [1] Per https://doc.rust-lang.org/core/str/fn.from_utf8.html#errors://// Returns `Err` if the slice is not UTF-8.const _: () = unsafe { unsafe_impl!(=> TryFromBytes for str; |c| { let c = c.transmute_with::<[u8], invariant::Valid, CastUnsized, BecauseImmutable>(); let c = c.unaligned_as_ref(); core::str::from_utf8(c).is_ok() })}; macro_rules! unsafe_impl_try_from_bytes_for_nonzero { ($($nonzero:ident[$prim:ty]),*) => { $( unsafe_impl!(=> TryFromBytes for $nonzero; |n| { let n = n.transmute_with::<Unalign<$prim>, invariant::Valid, CastSizedExact, BecauseImmutable>(); $nonzero::new(n.read().into_inner()).is_some() }); )* }} // `NonZeroXxx` is `IntoBytes`, but not `FromZeros` or `FromBytes`.//// SAFETY:// - `IntoBytes`: `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<NonZeroU8>`// and `Option<NonZeroI8>` 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.//// FIXME(#429):// - Add quotes from documentation.// - Add safety comment for `Immutable`. How can we prove that `NonZeroXxx`// doesn't contain any `UnsafeCell`s? It's obviously true, but it's not clear// how we'd prove it short of adding text to the stdlib docs that says so// explicitly, which likely wouldn't be accepted.//// [1] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroU8.html://// `NonZeroU8` is guaranteed to have the same layout and bit validity as `u8` with// the exception that 0 is not a valid instance.//// [2] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroI8.html://// `NonZeroI8` is guaranteed to have the same layout and bit validity as `i8` with// the exception that 0 is not a valid instance.#[allow(clippy::multiple_unsafe_ops_per_block)]const _: () = unsafe { unsafe_impl!(NonZeroU8: Immutable, IntoBytes, Unaligned); unsafe_impl!(NonZeroI8: Immutable, IntoBytes, Unaligned); assert_unaligned!(NonZeroU8, NonZeroI8); unsafe_impl!(NonZeroU16: Immutable, IntoBytes); unsafe_impl!(NonZeroI16: Immutable, IntoBytes); unsafe_impl!(NonZeroU32: Immutable, IntoBytes); unsafe_impl!(NonZeroI32: Immutable, IntoBytes); unsafe_impl!(NonZeroU64: Immutable, IntoBytes); unsafe_impl!(NonZeroI64: Immutable, IntoBytes); unsafe_impl!(NonZeroU128: Immutable, IntoBytes); unsafe_impl!(NonZeroI128: Immutable, IntoBytes); unsafe_impl!(NonZeroUsize: Immutable, IntoBytes); unsafe_impl!(NonZeroIsize: Immutable, IntoBytes); unsafe_impl_try_from_bytes_for_nonzero!( NonZeroU8[u8], NonZeroI8[i8], NonZeroU16[u16], NonZeroI16[i16], NonZeroU32[u32], NonZeroI32[i32], NonZeroU64[u64], NonZeroI64[i64], NonZeroU128[u128], NonZeroI128[i128], NonZeroUsize[usize], NonZeroIsize[isize] );}; // SAFETY:// - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`, `IntoBytes`:// The Rust compiler reuses `0` value to represent `None`, so// `size_of::<Option<NonZeroXxx>>() == size_of::<xxx>()`; see `NonZeroXxx`// documentation.// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that `Option<NonZeroU8>`// and `Option<NonZeroI8>` 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.//// [1] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroU8.html://// `Option<NonZeroU8>` is guaranteed to be compatible with `u8`, including in FFI.//// Thanks to the null pointer optimization, `NonZeroU8` and `Option<NonZeroU8>`// are guaranteed to have the same size and alignment://// [2] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroI8.html://// `Option<NonZeroI8>` is guaranteed to be compatible with `i8`, including in FFI.//// Thanks to the null pointer optimization, `NonZeroI8` and `Option<NonZeroI8>`// are guaranteed to have the same size and alignment:#[allow(clippy::multiple_unsafe_ops_per_block)]const _: () = unsafe { unsafe_impl!(Option<NonZeroU8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); unsafe_impl!(Option<NonZeroI8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_unaligned!(Option<NonZeroU8>, Option<NonZeroI8>); unsafe_impl!(Option<NonZeroU16>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroI16>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroU32>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroI32>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroU64>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroI64>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroU128>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroI128>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroUsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroIsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes);}; // SAFETY: While it's not fully documented, the consensus is that `Box<T>` does// not contain any `UnsafeCell`s for `T: Sized` [1]. This is not a complete// proof, but we are accepting this as a known risk per #1358.//// [1] https://github.com/rust-lang/unsafe-code-guidelines/issues/492#[cfg(feature = "alloc")]const _: () = unsafe { unsafe_impl!( #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] T: Sized => Immutable for Box<T> )}; // SAFETY: The following types can be transmuted from `[0u8; size_of::<T>()]`. [1]//// [1] Per https://doc.rust-lang.org/1.89.0/core/option/index.html#representation://// Rust guarantees to optimize the following types `T` such that [`Option<T>`]// has the same size and alignment as `T`. In some of these cases, Rust// further guarantees that `transmute::<_, Option<T>>([0u8; size_of::<T>()])`// is sound and produces `Option::<T>::None`. These cases are identified by// the second column://// | `T` | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? |// |-----------------------------------|-----------------------------------------------------------|// | [`Box<U>`] | when `U: Sized` |// | `&U` | when `U: Sized` |// | `&mut U` | when `U: Sized` |// | [`ptr::NonNull<U>`] | when `U: Sized` |// | `fn`, `extern "C" fn`[^extern_fn] | always |//// [^extern_fn]: this remains true for `unsafe` variants, any argument/return// types, and any other ABI: `[unsafe] extern "abi" fn` (_e.g._, `extern// "system" fn`)#[allow(clippy::multiple_unsafe_ops_per_block)]const _: () = unsafe { #[cfg(feature = "alloc")] unsafe_impl!( #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] T => TryFromBytes for Option<Box<T>>; |c| pointer::is_zeroed(c) ); #[cfg(feature = "alloc")] unsafe_impl!( #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] T => FromZeros for Option<Box<T>> ); unsafe_impl!( T => TryFromBytes for Option<&'_ T>; |c| pointer::is_zeroed(c) ); unsafe_impl!(T => FromZeros for Option<&'_ T>); unsafe_impl!( T => TryFromBytes for Option<&'_ mut T>; |c| pointer::is_zeroed(c) ); unsafe_impl!(T => FromZeros for Option<&'_ mut T>); unsafe_impl!( T => TryFromBytes for Option<NonNull<T>>; |c| pointer::is_zeroed(c) ); unsafe_impl!(T => FromZeros for Option<NonNull<T>>); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_fn!(...)); unsafe_impl_for_power_set!( A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_fn!(...); |c| pointer::is_zeroed(c) ); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_unsafe_fn!(...)); unsafe_impl_for_power_set!( A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_unsafe_fn!(...); |c| pointer::is_zeroed(c) ); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_extern_c_fn!(...)); unsafe_impl_for_power_set!( A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_extern_c_fn!(...); |c| pointer::is_zeroed(c) ); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_unsafe_extern_c_fn!(...)); unsafe_impl_for_power_set!( A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_unsafe_extern_c_fn!(...); |c| pointer::is_zeroed(c) );}; // SAFETY: `[unsafe] [extern "C"] fn()` self-evidently do not contain// `UnsafeCell`s. This is not a proof, but we are accepting this as a known risk// per #1358.#[allow(clippy::multiple_unsafe_ops_per_block)]const _: () = unsafe { unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_fn!(...)); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_unsafe_fn!(...)); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_extern_c_fn!(...)); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_unsafe_extern_c_fn!(...));}; #[cfg(all( not(no_zerocopy_target_has_atomics_1_60_0), any( target_has_atomic = "8", target_has_atomic = "16", target_has_atomic = "32", target_has_atomic = "64", target_has_atomic = "ptr" )))]#[cfg_attr(doc_cfg, doc(cfg(rust = "1.60.0")))]mod atomics { use super::*; macro_rules! impl_traits_for_atomics { ($($atomics:tt [$primitives:ty]),* $(,)?) => { $( impl_known_layout!($atomics); impl_for_transmute_from!(=> FromZeros for $atomics [$primitives]); impl_for_transmute_from!(=> FromBytes for $atomics [$primitives]); impl_for_transmute_from!(=> TryFromBytes for $atomics [$primitives]); impl_for_transmute_from!(=> IntoBytes for $atomics [$primitives]); )* }; } /// Implements `TransmuteFrom` for `$atomic`, `$prim`, and /// `UnsafeCell<$prim>`. /// /// # Safety /// /// `$atomic` must have the same size and bit validity as `$prim`. macro_rules! unsafe_impl_transmute_from_for_atomic { ($($($tyvar:ident)? => $atomic:ty [$prim:ty]),*) => {{ crate::util::macros::__unsafe(); use crate::pointer::{SizeEq, TransmuteFrom, invariant::Valid}; $( // SAFETY: The caller promised that `$atomic` and `$prim` have // the same size and bit validity. unsafe impl<$($tyvar)?> TransmuteFrom<$atomic, Valid, Valid> for $prim {} // SAFETY: The caller promised that `$atomic` and `$prim` have // the same size and bit validity. unsafe impl<$($tyvar)?> TransmuteFrom<$prim, Valid, Valid> for $atomic {} impl<$($tyvar)?> SizeEq<ReadOnly<$atomic>> for ReadOnly<$prim> { type CastFrom = $crate::pointer::cast::CastSizedExact; } // SAFETY: The caller promised that `$atomic` and `$prim` have // the same bit validity. `UnsafeCell<T>` has the same bit // validity as `T` [1]. // // [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.UnsafeCell.html#memory-layout: // // `UnsafeCell<T>` has the same in-memory representation as // its inner type `T`. A consequence of this guarantee is that // it is possible to convert between `T` and `UnsafeCell<T>`. unsafe impl<$($tyvar)?> TransmuteFrom<$atomic, Valid, Valid> for core::cell::UnsafeCell<$prim> {} // SAFETY: See previous safety comment. unsafe impl<$($tyvar)?> TransmuteFrom<core::cell::UnsafeCell<$prim>, Valid, Valid> for $atomic {} )* }}; } #[cfg(target_has_atomic = "8")] #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "8")))] mod atomic_8 { use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8}; use super::*; impl_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]); impl_known_layout!(AtomicBool); impl_for_transmute_from!(=> FromZeros for AtomicBool [bool]); impl_for_transmute_from!(=> TryFromBytes for AtomicBool [bool]); impl_for_transmute_from!(=> IntoBytes for AtomicBool [bool]); // SAFETY: Per [1], `AtomicBool`, `AtomicU8`, and `AtomicI8` have the // same size as `bool`, `u8`, and `i8` respectively. Since a type's // alignment cannot be smaller than 1 [2], and since its alignment // cannot be greater than its size [3], the only possible value for the // alignment is 1. Thus, it is sound to implement `Unaligned`. // // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU8.html: // // This type has the same size, alignment, and bit validity as the // underlying integer type // // [2] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment: // // Alignment is measured in bytes, and must be at least 1. // // [3] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment: // // The size of a value is always a multiple of its alignment. #[allow(clippy::multiple_unsafe_ops_per_block)] const _: () = unsafe { unsafe_impl!(AtomicBool: Unaligned); unsafe_impl!(AtomicU8: Unaligned); unsafe_impl!(AtomicI8: Unaligned); assert_unaligned!(AtomicBool, AtomicU8, AtomicI8); }; // SAFETY: `AtomicU8`, `AtomicI8`, and `AtomicBool` have the same size // and bit validity as `u8`, `i8`, and `bool` respectively [1][2][3]. // // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU8.html: // // This type has the same size, alignment, and bit validity as the // underlying integer type, `u8`.Lines 1–500 of 2389. Load more
// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT // // Copyright 2024 The Fuchsia Authors // // Licensed under the 2-Clause BSD License <LICENSE-BSD or // https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0 // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option. // This file may not be copied, modified, or distributed except according to // those terms. use core::{ cell::{Cell, UnsafeCell}, mem::MaybeUninit as CoreMaybeUninit, ptr::NonNull, }; use super::*; use crate::pointer::cast::{CastSizedExact, CastUnsized}; // 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." // - `Immutable`: `()` self-evidently does not contain any `UnsafeCell`s. // - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: There is only // one possible sequence of 0 bytes, and `()` is inhabited. // - `IntoBytes`: Since `()` has size 0, it contains no padding bytes. // - `Unaligned`: `()` has alignment 1. // // [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#tuple-layout #[allow(clippy::multiple_unsafe_ops_per_block)] const _: () = unsafe { unsafe_impl!((): Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_unaligned!(()); }; // SAFETY: // - `Immutable`: These types self-evidently do not contain any `UnsafeCell`s. // - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: all bit // patterns are valid for numeric types [1] // - `IntoBytes`: 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/1.81.0/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::<T>()]`. An uninitialized byte is // not a valid `u8`. // // [2] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#primitive-data-layout // // [3] Per https://doc.rust-lang.org/1.81.0/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/1.81.0/reference/type-layout.html#size-and-alignment: // // The size of a value is always a multiple of its alignment. // // FIXME(#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]. #[allow(clippy::multiple_unsafe_ops_per_block)] const _: () = unsafe { unsafe_impl!(u8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); unsafe_impl!(i8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_unaligned!(u8, i8); unsafe_impl!(u16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(i16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(u32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(i32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(u64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(i64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(u128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(i128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(usize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(isize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(f32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(f64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); #[cfg(feature = "float-nightly")] unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); #[cfg(feature = "float-nightly")] unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); }; // SAFETY: // - `Immutable`: `bool` self-evidently does not contain any `UnsafeCell`s. // - `FromZeros`: Valid since "[t]he value false has the bit pattern 0x00" [1]. // - `IntoBytes`: 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/1.81.0/reference/types/boolean.html #[allow(clippy::multiple_unsafe_ops_per_block)] const _: () = unsafe { unsafe_impl!(bool: Immutable, FromZeros, IntoBytes, Unaligned) }; assert_unaligned!(bool); // SAFETY: The impl must only return `true` for its argument if the original // `Maybe<bool>` 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` [1]. // // [1] Per https://doc.rust-lang.org/1.81.0/reference/types/boolean.html: // // The value false has the bit pattern 0x00 and the value true has the bit // pattern 0x01. const _: () = unsafe { unsafe_impl!(=> TryFromBytes for bool; |byte| { let byte = byte.transmute_with::<u8, invariant::Valid, CastSizedExact, BecauseImmutable>(); *byte.unaligned_as_ref() < 2 }) }; // SAFETY: // - `Immutable`: `char` self-evidently does not contain any `UnsafeCell`s. // - `FromZeros`: 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. // - `IntoBytes`: `char` is per reference [1] "represented as a 32-bit unsigned // word" (`u32`) which is `IntoBytes`. Note that unlike `u32`, not all bit // patterns are valid for `char`. // // [1] https://doc.rust-lang.org/1.81.0/reference/types/textual.html #[allow(clippy::multiple_unsafe_ops_per_block)] const _: () = unsafe { unsafe_impl!(char: Immutable, FromZeros, IntoBytes) }; // SAFETY: The impl must only return `true` for its argument if the original // `Maybe<char>` refers to a valid `char`. `char::from_u32` guarantees that it // returns `None` if its input is not a valid `char` [1]. // // [1] 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`. const _: () = unsafe { unsafe_impl!(=> TryFromBytes for char; |c| { let c = c.transmute_with::<Unalign<u32>, invariant::Valid, CastSizedExact, BecauseImmutable>(); let c = c.read().into_inner(); char::from_u32(c).is_some() }); }; // SAFETY: Per the Reference [1], `str` has the same layout as `[u8]`. // - `Immutable`: `[u8]` does not contain any `UnsafeCell`s. // - `FromZeros`, `IntoBytes`, `Unaligned`: `[u8]` is `FromZeros`, `IntoBytes`, // and `Unaligned`. // // Note that we don't `assert_unaligned!(str)` because `assert_unaligned!` uses // `align_of`, which only works for `Sized` types. // // FIXME(#429): Improve safety proof for `FromZeros` and `IntoBytes`; having the same // layout as `[u8]` isn't sufficient. // // [1] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#str-layout: // // String slices are a UTF-8 representation of characters that have the same // layout as slices of type `[u8]`. #[allow(clippy::multiple_unsafe_ops_per_block)] const _: () = unsafe { unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unaligned) }; // SAFETY: The impl must only return `true` for its argument if the original // `Maybe<str>` refers to a valid `str`. `str::from_utf8` guarantees that it // returns `Err` if its input is not a valid `str` [1]. // // [1] Per https://doc.rust-lang.org/core/str/fn.from_utf8.html#errors: // // Returns `Err` if the slice is not UTF-8. const _: () = unsafe { unsafe_impl!(=> TryFromBytes for str; |c| { let c = c.transmute_with::<[u8], invariant::Valid, CastUnsized, BecauseImmutable>(); let c = c.unaligned_as_ref(); core::str::from_utf8(c).is_ok() }) }; macro_rules! unsafe_impl_try_from_bytes_for_nonzero { ($($nonzero:ident[$prim:ty]),*) => { $( unsafe_impl!(=> TryFromBytes for $nonzero; |n| { let n = n.transmute_with::<Unalign<$prim>, invariant::Valid, CastSizedExact, BecauseImmutable>(); $nonzero::new(n.read().into_inner()).is_some() }); )* } } // `NonZeroXxx` is `IntoBytes`, but not `FromZeros` or `FromBytes`. // // SAFETY: // - `IntoBytes`: `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<NonZeroU8>` // and `Option<NonZeroI8>` 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. // // FIXME(#429): // - Add quotes from documentation. // - Add safety comment for `Immutable`. How can we prove that `NonZeroXxx` // doesn't contain any `UnsafeCell`s? It's obviously true, but it's not clear // how we'd prove it short of adding text to the stdlib docs that says so // explicitly, which likely wouldn't be accepted. // // [1] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroU8.html: // // `NonZeroU8` is guaranteed to have the same layout and bit validity as `u8` with // the exception that 0 is not a valid instance. // // [2] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroI8.html: // // `NonZeroI8` is guaranteed to have the same layout and bit validity as `i8` with // the exception that 0 is not a valid instance. #[allow(clippy::multiple_unsafe_ops_per_block)] const _: () = unsafe { unsafe_impl!(NonZeroU8: Immutable, IntoBytes, Unaligned); unsafe_impl!(NonZeroI8: Immutable, IntoBytes, Unaligned); assert_unaligned!(NonZeroU8, NonZeroI8); unsafe_impl!(NonZeroU16: Immutable, IntoBytes); unsafe_impl!(NonZeroI16: Immutable, IntoBytes); unsafe_impl!(NonZeroU32: Immutable, IntoBytes); unsafe_impl!(NonZeroI32: Immutable, IntoBytes); unsafe_impl!(NonZeroU64: Immutable, IntoBytes); unsafe_impl!(NonZeroI64: Immutable, IntoBytes); unsafe_impl!(NonZeroU128: Immutable, IntoBytes); unsafe_impl!(NonZeroI128: Immutable, IntoBytes); unsafe_impl!(NonZeroUsize: Immutable, IntoBytes); unsafe_impl!(NonZeroIsize: Immutable, IntoBytes); unsafe_impl_try_from_bytes_for_nonzero!( NonZeroU8[u8], NonZeroI8[i8], NonZeroU16[u16], NonZeroI16[i16], NonZeroU32[u32], NonZeroI32[i32], NonZeroU64[u64], NonZeroI64[i64], NonZeroU128[u128], NonZeroI128[i128], NonZeroUsize[usize], NonZeroIsize[isize] ); }; // SAFETY: // - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`, `IntoBytes`: // The Rust compiler reuses `0` value to represent `None`, so // `size_of::<Option<NonZeroXxx>>() == size_of::<xxx>()`; see `NonZeroXxx` // documentation. // - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that `Option<NonZeroU8>` // and `Option<NonZeroI8>` 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. // // [1] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroU8.html: // // `Option<NonZeroU8>` is guaranteed to be compatible with `u8`, including in FFI. // // Thanks to the null pointer optimization, `NonZeroU8` and `Option<NonZeroU8>` // are guaranteed to have the same size and alignment: // // [2] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroI8.html: // // `Option<NonZeroI8>` is guaranteed to be compatible with `i8`, including in FFI. // // Thanks to the null pointer optimization, `NonZeroI8` and `Option<NonZeroI8>` // are guaranteed to have the same size and alignment: #[allow(clippy::multiple_unsafe_ops_per_block)] const _: () = unsafe { unsafe_impl!(Option<NonZeroU8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); unsafe_impl!(Option<NonZeroI8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned); assert_unaligned!(Option<NonZeroU8>, Option<NonZeroI8>); unsafe_impl!(Option<NonZeroU16>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroI16>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroU32>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroI32>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroU64>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroI64>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroU128>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroI128>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroUsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes); unsafe_impl!(Option<NonZeroIsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes); }; // SAFETY: While it's not fully documented, the consensus is that `Box<T>` does // not contain any `UnsafeCell`s for `T: Sized` [1]. This is not a complete // proof, but we are accepting this as a known risk per #1358. // // [1] https://github.com/rust-lang/unsafe-code-guidelines/issues/492 #[cfg(feature = "alloc")] const _: () = unsafe { unsafe_impl!( #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] T: Sized => Immutable for Box<T> ) }; // SAFETY: The following types can be transmuted from `[0u8; size_of::<T>()]`. [1] // // [1] Per https://doc.rust-lang.org/1.89.0/core/option/index.html#representation: // // Rust guarantees to optimize the following types `T` such that [`Option<T>`] // has the same size and alignment as `T`. In some of these cases, Rust // further guarantees that `transmute::<_, Option<T>>([0u8; size_of::<T>()])` // is sound and produces `Option::<T>::None`. These cases are identified by // the second column: // // | `T` | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? | // |-----------------------------------|-----------------------------------------------------------| // | [`Box<U>`] | when `U: Sized` | // | `&U` | when `U: Sized` | // | `&mut U` | when `U: Sized` | // | [`ptr::NonNull<U>`] | when `U: Sized` | // | `fn`, `extern "C" fn`[^extern_fn] | always | // // [^extern_fn]: this remains true for `unsafe` variants, any argument/return // types, and any other ABI: `[unsafe] extern "abi" fn` (_e.g._, `extern // "system" fn`) #[allow(clippy::multiple_unsafe_ops_per_block)] const _: () = unsafe { #[cfg(feature = "alloc")] unsafe_impl!( #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] T => TryFromBytes for Option<Box<T>>; |c| pointer::is_zeroed(c) ); #[cfg(feature = "alloc")] unsafe_impl!( #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] T => FromZeros for Option<Box<T>> ); unsafe_impl!( T => TryFromBytes for Option<&'_ T>; |c| pointer::is_zeroed(c) ); unsafe_impl!(T => FromZeros for Option<&'_ T>); unsafe_impl!( T => TryFromBytes for Option<&'_ mut T>; |c| pointer::is_zeroed(c) ); unsafe_impl!(T => FromZeros for Option<&'_ mut T>); unsafe_impl!( T => TryFromBytes for Option<NonNull<T>>; |c| pointer::is_zeroed(c) ); unsafe_impl!(T => FromZeros for Option<NonNull<T>>); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_fn!(...)); unsafe_impl_for_power_set!( A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_fn!(...); |c| pointer::is_zeroed(c) ); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_unsafe_fn!(...)); unsafe_impl_for_power_set!( A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_unsafe_fn!(...); |c| pointer::is_zeroed(c) ); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_extern_c_fn!(...)); unsafe_impl_for_power_set!( A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_extern_c_fn!(...); |c| pointer::is_zeroed(c) ); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_unsafe_extern_c_fn!(...)); unsafe_impl_for_power_set!( A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_unsafe_extern_c_fn!(...); |c| pointer::is_zeroed(c) ); }; // SAFETY: `[unsafe] [extern "C"] fn()` self-evidently do not contain // `UnsafeCell`s. This is not a proof, but we are accepting this as a known risk // per #1358. #[allow(clippy::multiple_unsafe_ops_per_block)] const _: () = unsafe { unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_fn!(...)); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_unsafe_fn!(...)); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_extern_c_fn!(...)); unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_unsafe_extern_c_fn!(...)); }; #[cfg(all( not(no_zerocopy_target_has_atomics_1_60_0), any( target_has_atomic = "8", target_has_atomic = "16", target_has_atomic = "32", target_has_atomic = "64", target_has_atomic = "ptr" ) ))] #[cfg_attr(doc_cfg, doc(cfg(rust = "1.60.0")))] mod atomics { use super::*; macro_rules! impl_traits_for_atomics { ($($atomics:tt [$primitives:ty]),* $(,)?) => { $( impl_known_layout!($atomics); impl_for_transmute_from!(=> FromZeros for $atomics [$primitives]); impl_for_transmute_from!(=> FromBytes for $atomics [$primitives]); impl_for_transmute_from!(=> TryFromBytes for $atomics [$primitives]); impl_for_transmute_from!(=> IntoBytes for $atomics [$primitives]); )* }; } /// Implements `TransmuteFrom` for `$atomic`, `$prim`, and /// `UnsafeCell<$prim>`. /// /// # Safety /// /// `$atomic` must have the same size and bit validity as `$prim`. macro_rules! unsafe_impl_transmute_from_for_atomic { ($($($tyvar:ident)? => $atomic:ty [$prim:ty]),*) => {{ crate::util::macros::__unsafe(); use crate::pointer::{SizeEq, TransmuteFrom, invariant::Valid}; $( // SAFETY: The caller promised that `$atomic` and `$prim` have // the same size and bit validity. unsafe impl<$($tyvar)?> TransmuteFrom<$atomic, Valid, Valid> for $prim {} // SAFETY: The caller promised that `$atomic` and `$prim` have // the same size and bit validity. unsafe impl<$($tyvar)?> TransmuteFrom<$prim, Valid, Valid> for $atomic {} impl<$($tyvar)?> SizeEq<ReadOnly<$atomic>> for ReadOnly<$prim> { type CastFrom = $crate::pointer::cast::CastSizedExact; } // SAFETY: The caller promised that `$atomic` and `$prim` have // the same bit validity. `UnsafeCell<T>` has the same bit // validity as `T` [1]. // // [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.UnsafeCell.html#memory-layout: // // `UnsafeCell<T>` has the same in-memory representation as // its inner type `T`. A consequence of this guarantee is that // it is possible to convert between `T` and `UnsafeCell<T>`. unsafe impl<$($tyvar)?> TransmuteFrom<$atomic, Valid, Valid> for core::cell::UnsafeCell<$prim> {} // SAFETY: See previous safety comment. unsafe impl<$($tyvar)?> TransmuteFrom<core::cell::UnsafeCell<$prim>, Valid, Valid> for $atomic {} )* }}; } #[cfg(target_has_atomic = "8")] #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "8")))] mod atomic_8 { use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8}; use super::*; impl_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]); impl_known_layout!(AtomicBool); impl_for_transmute_from!(=> FromZeros for AtomicBool [bool]); impl_for_transmute_from!(=> TryFromBytes for AtomicBool [bool]); impl_for_transmute_from!(=> IntoBytes for AtomicBool [bool]); // SAFETY: Per [1], `AtomicBool`, `AtomicU8`, and `AtomicI8` have the // same size as `bool`, `u8`, and `i8` respectively. Since a type's // alignment cannot be smaller than 1 [2], and since its alignment // cannot be greater than its size [3], the only possible value for the // alignment is 1. Thus, it is sound to implement `Unaligned`. // // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU8.html: // // This type has the same size, alignment, and bit validity as the // underlying integer type // // [2] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment: // // Alignment is measured in bytes, and must be at least 1. // // [3] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment: // // The size of a value is always a multiple of its alignment. #[allow(clippy::multiple_unsafe_ops_per_block)] const _: () = unsafe { unsafe_impl!(AtomicBool: Unaligned); unsafe_impl!(AtomicU8: Unaligned); unsafe_impl!(AtomicI8: Unaligned); assert_unaligned!(AtomicBool, AtomicU8, AtomicI8); }; // SAFETY: `AtomicU8`, `AtomicI8`, and `AtomicBool` have the same size // and bit validity as `u8`, `i8`, and `bool` respectively [1][2][3]. // // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU8.html: // // This type has the same size, alignment, and bit validity as the // underlying integer type, `u8`.