xref: /linux/rust/zerocopy/src/impls.rs (revision b079329b8691768962aa514b8f8c9077ca352459)
1*499dc02cSMiguel Ojeda // SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT
2*499dc02cSMiguel Ojeda 
3c3739801SMiguel Ojeda // Copyright 2024 The Fuchsia Authors
4c3739801SMiguel Ojeda //
5c3739801SMiguel Ojeda // Licensed under the 2-Clause BSD License <LICENSE-BSD or
6c3739801SMiguel Ojeda // https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
7c3739801SMiguel Ojeda // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
8c3739801SMiguel Ojeda // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
9c3739801SMiguel Ojeda // This file may not be copied, modified, or distributed except according to
10c3739801SMiguel Ojeda // those terms.
11c3739801SMiguel Ojeda 
12c3739801SMiguel Ojeda use core::{
13c3739801SMiguel Ojeda     cell::{Cell, UnsafeCell},
14c3739801SMiguel Ojeda     mem::MaybeUninit as CoreMaybeUninit,
15c3739801SMiguel Ojeda     ptr::NonNull,
16c3739801SMiguel Ojeda };
17c3739801SMiguel Ojeda 
18c3739801SMiguel Ojeda use super::*;
19c3739801SMiguel Ojeda use crate::pointer::cast::{CastSizedExact, CastUnsized};
20c3739801SMiguel Ojeda 
21c3739801SMiguel Ojeda // SAFETY: Per the reference [1], "the unit tuple (`()`) ... is guaranteed as a
22c3739801SMiguel Ojeda // zero-sized type to have a size of 0 and an alignment of 1."
23c3739801SMiguel Ojeda // - `Immutable`: `()` self-evidently does not contain any `UnsafeCell`s.
24c3739801SMiguel Ojeda // - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: There is only
25c3739801SMiguel Ojeda //   one possible sequence of 0 bytes, and `()` is inhabited.
26c3739801SMiguel Ojeda // - `IntoBytes`: Since `()` has size 0, it contains no padding bytes.
27c3739801SMiguel Ojeda // - `Unaligned`: `()` has alignment 1.
28c3739801SMiguel Ojeda //
29c3739801SMiguel Ojeda // [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#tuple-layout
30c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
31c3739801SMiguel Ojeda const _: () = unsafe {
32c3739801SMiguel Ojeda     unsafe_impl!((): Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
33c3739801SMiguel Ojeda     assert_unaligned!(());
34c3739801SMiguel Ojeda };
35c3739801SMiguel Ojeda 
36c3739801SMiguel Ojeda // SAFETY:
37c3739801SMiguel Ojeda // - `Immutable`: These types self-evidently do not contain any `UnsafeCell`s.
38c3739801SMiguel Ojeda // - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: all bit
39c3739801SMiguel Ojeda //   patterns are valid for numeric types [1]
40c3739801SMiguel Ojeda // - `IntoBytes`: numeric types have no padding bytes [1]
41c3739801SMiguel Ojeda // - `Unaligned` (`u8` and `i8` only): The reference [2] specifies the size of
42c3739801SMiguel Ojeda //   `u8` and `i8` as 1 byte. We also know that:
43c3739801SMiguel Ojeda //   - Alignment is >= 1 [3]
44c3739801SMiguel Ojeda //   - Size is an integer multiple of alignment [4]
45c3739801SMiguel Ojeda //   - The only value >= 1 for which 1 is an integer multiple is 1 Therefore,
46c3739801SMiguel Ojeda //   the only possible alignment for `u8` and `i8` is 1.
47c3739801SMiguel Ojeda //
48c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/reference/types/numeric.html#bit-validity:
49c3739801SMiguel Ojeda //
50c3739801SMiguel Ojeda //     For every numeric type, `T`, the bit validity of `T` is equivalent to
51c3739801SMiguel Ojeda //     the bit validity of `[u8; size_of::<T>()]`. An uninitialized byte is
52c3739801SMiguel Ojeda //     not a valid `u8`.
53c3739801SMiguel Ojeda //
54c3739801SMiguel Ojeda // [2] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#primitive-data-layout
55c3739801SMiguel Ojeda //
56c3739801SMiguel Ojeda // [3] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment:
57c3739801SMiguel Ojeda //
58c3739801SMiguel Ojeda //     Alignment is measured in bytes, and must be at least 1.
59c3739801SMiguel Ojeda //
60c3739801SMiguel Ojeda // [4] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment:
61c3739801SMiguel Ojeda //
62c3739801SMiguel Ojeda //     The size of a value is always a multiple of its alignment.
63c3739801SMiguel Ojeda //
64c3739801SMiguel Ojeda // FIXME(#278): Once we've updated the trait docs to refer to `u8`s rather than
65c3739801SMiguel Ojeda // bits or bytes, update this comment, especially the reference to [1].
66c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
67c3739801SMiguel Ojeda const _: () = unsafe {
68c3739801SMiguel Ojeda     unsafe_impl!(u8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
69c3739801SMiguel Ojeda     unsafe_impl!(i8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
70c3739801SMiguel Ojeda     assert_unaligned!(u8, i8);
71c3739801SMiguel Ojeda     unsafe_impl!(u16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
72c3739801SMiguel Ojeda     unsafe_impl!(i16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
73c3739801SMiguel Ojeda     unsafe_impl!(u32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
74c3739801SMiguel Ojeda     unsafe_impl!(i32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
75c3739801SMiguel Ojeda     unsafe_impl!(u64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
76c3739801SMiguel Ojeda     unsafe_impl!(i64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
77c3739801SMiguel Ojeda     unsafe_impl!(u128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
78c3739801SMiguel Ojeda     unsafe_impl!(i128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
79c3739801SMiguel Ojeda     unsafe_impl!(usize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
80c3739801SMiguel Ojeda     unsafe_impl!(isize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
81c3739801SMiguel Ojeda     unsafe_impl!(f32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
82c3739801SMiguel Ojeda     unsafe_impl!(f64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
83c3739801SMiguel Ojeda     #[cfg(feature = "float-nightly")]
84c3739801SMiguel Ojeda     unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
85c3739801SMiguel Ojeda     #[cfg(feature = "float-nightly")]
86c3739801SMiguel Ojeda     unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
87c3739801SMiguel Ojeda };
88c3739801SMiguel Ojeda 
89c3739801SMiguel Ojeda // SAFETY:
90c3739801SMiguel Ojeda // - `Immutable`: `bool` self-evidently does not contain any `UnsafeCell`s.
91c3739801SMiguel Ojeda // - `FromZeros`: Valid since "[t]he value false has the bit pattern 0x00" [1].
92c3739801SMiguel Ojeda // - `IntoBytes`: Since "the boolean type has a size and alignment of 1 each"
93c3739801SMiguel Ojeda //   and "The value false has the bit pattern 0x00 and the value true has the
94c3739801SMiguel Ojeda //   bit pattern 0x01" [1]. Thus, the only byte of the bool is always
95c3739801SMiguel Ojeda //   initialized.
96c3739801SMiguel Ojeda // - `Unaligned`: Per the reference [1], "[a]n object with the boolean type has
97c3739801SMiguel Ojeda //   a size and alignment of 1 each."
98c3739801SMiguel Ojeda //
99c3739801SMiguel Ojeda // [1] https://doc.rust-lang.org/1.81.0/reference/types/boolean.html
100c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
101c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(bool: Immutable, FromZeros, IntoBytes, Unaligned) };
102c3739801SMiguel Ojeda assert_unaligned!(bool);
103c3739801SMiguel Ojeda 
104c3739801SMiguel Ojeda // SAFETY: The impl must only return `true` for its argument if the original
105c3739801SMiguel Ojeda // `Maybe<bool>` refers to a valid `bool`. We only return true if the `u8` value
106c3739801SMiguel Ojeda // is 0 or 1, and both of these are valid values for `bool` [1].
107c3739801SMiguel Ojeda //
108c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/reference/types/boolean.html:
109c3739801SMiguel Ojeda //
110c3739801SMiguel Ojeda //   The value false has the bit pattern 0x00 and the value true has the bit
111c3739801SMiguel Ojeda //   pattern 0x01.
112c3739801SMiguel Ojeda const _: () = unsafe {
113c3739801SMiguel Ojeda     unsafe_impl!(=> TryFromBytes for bool; |byte| {
114c3739801SMiguel Ojeda         let byte = byte.transmute_with::<u8, invariant::Valid, CastSizedExact, BecauseImmutable>();
115c3739801SMiguel Ojeda         *byte.unaligned_as_ref() < 2
116c3739801SMiguel Ojeda     })
117c3739801SMiguel Ojeda };
118c3739801SMiguel Ojeda 
119c3739801SMiguel Ojeda // SAFETY:
120c3739801SMiguel Ojeda // - `Immutable`: `char` self-evidently does not contain any `UnsafeCell`s.
121c3739801SMiguel Ojeda // - `FromZeros`: Per reference [1], "[a] value of type char is a Unicode scalar
122c3739801SMiguel Ojeda //   value (i.e. a code point that is not a surrogate), represented as a 32-bit
123c3739801SMiguel Ojeda //   unsigned word in the 0x0000 to 0xD7FF or 0xE000 to 0x10FFFF range" which
124c3739801SMiguel Ojeda //   contains 0x0000.
125c3739801SMiguel Ojeda // - `IntoBytes`: `char` is per reference [1] "represented as a 32-bit unsigned
126c3739801SMiguel Ojeda //   word" (`u32`) which is `IntoBytes`. Note that unlike `u32`, not all bit
127c3739801SMiguel Ojeda //   patterns are valid for `char`.
128c3739801SMiguel Ojeda //
129c3739801SMiguel Ojeda // [1] https://doc.rust-lang.org/1.81.0/reference/types/textual.html
130c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
131c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(char: Immutable, FromZeros, IntoBytes) };
132c3739801SMiguel Ojeda 
133c3739801SMiguel Ojeda // SAFETY: The impl must only return `true` for its argument if the original
134c3739801SMiguel Ojeda // `Maybe<char>` refers to a valid `char`. `char::from_u32` guarantees that it
135c3739801SMiguel Ojeda // returns `None` if its input is not a valid `char` [1].
136c3739801SMiguel Ojeda //
137c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32:
138c3739801SMiguel Ojeda //
139c3739801SMiguel Ojeda //   `from_u32()` will return `None` if the input is not a valid value for a
140c3739801SMiguel Ojeda //   `char`.
141c3739801SMiguel Ojeda const _: () = unsafe {
142c3739801SMiguel Ojeda     unsafe_impl!(=> TryFromBytes for char; |c| {
143c3739801SMiguel Ojeda         let c = c.transmute_with::<Unalign<u32>, invariant::Valid, CastSizedExact, BecauseImmutable>();
144c3739801SMiguel Ojeda         let c = c.read().into_inner();
145c3739801SMiguel Ojeda         char::from_u32(c).is_some()
146c3739801SMiguel Ojeda     });
147c3739801SMiguel Ojeda };
148c3739801SMiguel Ojeda 
149c3739801SMiguel Ojeda // SAFETY: Per the Reference [1], `str` has the same layout as `[u8]`.
150c3739801SMiguel Ojeda // - `Immutable`: `[u8]` does not contain any `UnsafeCell`s.
151c3739801SMiguel Ojeda // - `FromZeros`, `IntoBytes`, `Unaligned`: `[u8]` is `FromZeros`, `IntoBytes`,
152c3739801SMiguel Ojeda //   and `Unaligned`.
153c3739801SMiguel Ojeda //
154c3739801SMiguel Ojeda // Note that we don't `assert_unaligned!(str)` because `assert_unaligned!` uses
155c3739801SMiguel Ojeda // `align_of`, which only works for `Sized` types.
156c3739801SMiguel Ojeda //
157c3739801SMiguel Ojeda // FIXME(#429): Improve safety proof for `FromZeros` and `IntoBytes`; having the same
158c3739801SMiguel Ojeda // layout as `[u8]` isn't sufficient.
159c3739801SMiguel Ojeda //
160c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#str-layout:
161c3739801SMiguel Ojeda //
162c3739801SMiguel Ojeda //   String slices are a UTF-8 representation of characters that have the same
163c3739801SMiguel Ojeda //   layout as slices of type `[u8]`.
164c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
165c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unaligned) };
166c3739801SMiguel Ojeda 
167c3739801SMiguel Ojeda // SAFETY: The impl must only return `true` for its argument if the original
168c3739801SMiguel Ojeda // `Maybe<str>` refers to a valid `str`. `str::from_utf8` guarantees that it
169c3739801SMiguel Ojeda // returns `Err` if its input is not a valid `str` [1].
170c3739801SMiguel Ojeda //
171c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/core/str/fn.from_utf8.html#errors:
172c3739801SMiguel Ojeda //
173c3739801SMiguel Ojeda //   Returns `Err` if the slice is not UTF-8.
174c3739801SMiguel Ojeda const _: () = unsafe {
175c3739801SMiguel Ojeda     unsafe_impl!(=> TryFromBytes for str; |c| {
176c3739801SMiguel Ojeda         let c = c.transmute_with::<[u8], invariant::Valid, CastUnsized, BecauseImmutable>();
177c3739801SMiguel Ojeda         let c = c.unaligned_as_ref();
178c3739801SMiguel Ojeda         core::str::from_utf8(c).is_ok()
179c3739801SMiguel Ojeda     })
180c3739801SMiguel Ojeda };
181c3739801SMiguel Ojeda 
182c3739801SMiguel Ojeda macro_rules! unsafe_impl_try_from_bytes_for_nonzero {
183c3739801SMiguel Ojeda     ($($nonzero:ident[$prim:ty]),*) => {
184c3739801SMiguel Ojeda         $(
185c3739801SMiguel Ojeda             unsafe_impl!(=> TryFromBytes for $nonzero; |n| {
186c3739801SMiguel Ojeda                 let n = n.transmute_with::<Unalign<$prim>, invariant::Valid, CastSizedExact, BecauseImmutable>();
187c3739801SMiguel Ojeda                 $nonzero::new(n.read().into_inner()).is_some()
188c3739801SMiguel Ojeda             });
189c3739801SMiguel Ojeda         )*
190c3739801SMiguel Ojeda     }
191c3739801SMiguel Ojeda }
192c3739801SMiguel Ojeda 
193c3739801SMiguel Ojeda // `NonZeroXxx` is `IntoBytes`, but not `FromZeros` or `FromBytes`.
194c3739801SMiguel Ojeda //
195c3739801SMiguel Ojeda // SAFETY:
196c3739801SMiguel Ojeda // - `IntoBytes`: `NonZeroXxx` has the same layout as its associated primitive.
197c3739801SMiguel Ojeda //    Since it is the same size, this guarantees it has no padding - integers
198c3739801SMiguel Ojeda //    have no padding, and there's no room for padding if it can represent all
199c3739801SMiguel Ojeda //    of the same values except 0.
200c3739801SMiguel Ojeda // - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that `Option<NonZeroU8>`
201c3739801SMiguel Ojeda //   and `Option<NonZeroI8>` both have size 1. [1] [2] This is worded in a way
202c3739801SMiguel Ojeda //   that makes it unclear whether it's meant as a guarantee, but given the
203c3739801SMiguel Ojeda //   purpose of those types, it's virtually unthinkable that that would ever
204c3739801SMiguel Ojeda //   change. `Option` cannot be smaller than its contained type, which implies
205c3739801SMiguel Ojeda //   that, and `NonZeroX8` are of size 1 or 0. `NonZeroX8` can represent
206c3739801SMiguel Ojeda //   multiple states, so they cannot be 0 bytes, which means that they must be 1
207c3739801SMiguel Ojeda //   byte. The only valid alignment for a 1-byte type is 1.
208c3739801SMiguel Ojeda //
209c3739801SMiguel Ojeda // FIXME(#429):
210c3739801SMiguel Ojeda // - Add quotes from documentation.
211c3739801SMiguel Ojeda // - Add safety comment for `Immutable`. How can we prove that `NonZeroXxx`
212c3739801SMiguel Ojeda //   doesn't contain any `UnsafeCell`s? It's obviously true, but it's not clear
213c3739801SMiguel Ojeda //   how we'd prove it short of adding text to the stdlib docs that says so
214c3739801SMiguel Ojeda //   explicitly, which likely wouldn't be accepted.
215c3739801SMiguel Ojeda //
216c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroU8.html:
217c3739801SMiguel Ojeda //
218c3739801SMiguel Ojeda //     `NonZeroU8` is guaranteed to have the same layout and bit validity as `u8` with
219c3739801SMiguel Ojeda //     the exception that 0 is not a valid instance.
220c3739801SMiguel Ojeda //
221c3739801SMiguel Ojeda // [2] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroI8.html:
222c3739801SMiguel Ojeda //
223c3739801SMiguel Ojeda //     `NonZeroI8` is guaranteed to have the same layout and bit validity as `i8` with
224c3739801SMiguel Ojeda //     the exception that 0 is not a valid instance.
225c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
226c3739801SMiguel Ojeda const _: () = unsafe {
227c3739801SMiguel Ojeda     unsafe_impl!(NonZeroU8: Immutable, IntoBytes, Unaligned);
228c3739801SMiguel Ojeda     unsafe_impl!(NonZeroI8: Immutable, IntoBytes, Unaligned);
229c3739801SMiguel Ojeda     assert_unaligned!(NonZeroU8, NonZeroI8);
230c3739801SMiguel Ojeda     unsafe_impl!(NonZeroU16: Immutable, IntoBytes);
231c3739801SMiguel Ojeda     unsafe_impl!(NonZeroI16: Immutable, IntoBytes);
232c3739801SMiguel Ojeda     unsafe_impl!(NonZeroU32: Immutable, IntoBytes);
233c3739801SMiguel Ojeda     unsafe_impl!(NonZeroI32: Immutable, IntoBytes);
234c3739801SMiguel Ojeda     unsafe_impl!(NonZeroU64: Immutable, IntoBytes);
235c3739801SMiguel Ojeda     unsafe_impl!(NonZeroI64: Immutable, IntoBytes);
236c3739801SMiguel Ojeda     unsafe_impl!(NonZeroU128: Immutable, IntoBytes);
237c3739801SMiguel Ojeda     unsafe_impl!(NonZeroI128: Immutable, IntoBytes);
238c3739801SMiguel Ojeda     unsafe_impl!(NonZeroUsize: Immutable, IntoBytes);
239c3739801SMiguel Ojeda     unsafe_impl!(NonZeroIsize: Immutable, IntoBytes);
240c3739801SMiguel Ojeda     unsafe_impl_try_from_bytes_for_nonzero!(
241c3739801SMiguel Ojeda         NonZeroU8[u8],
242c3739801SMiguel Ojeda         NonZeroI8[i8],
243c3739801SMiguel Ojeda         NonZeroU16[u16],
244c3739801SMiguel Ojeda         NonZeroI16[i16],
245c3739801SMiguel Ojeda         NonZeroU32[u32],
246c3739801SMiguel Ojeda         NonZeroI32[i32],
247c3739801SMiguel Ojeda         NonZeroU64[u64],
248c3739801SMiguel Ojeda         NonZeroI64[i64],
249c3739801SMiguel Ojeda         NonZeroU128[u128],
250c3739801SMiguel Ojeda         NonZeroI128[i128],
251c3739801SMiguel Ojeda         NonZeroUsize[usize],
252c3739801SMiguel Ojeda         NonZeroIsize[isize]
253c3739801SMiguel Ojeda     );
254c3739801SMiguel Ojeda };
255c3739801SMiguel Ojeda 
256c3739801SMiguel Ojeda // SAFETY:
257c3739801SMiguel Ojeda // - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`, `IntoBytes`:
258c3739801SMiguel Ojeda //   The Rust compiler reuses `0` value to represent `None`, so
259c3739801SMiguel Ojeda //   `size_of::<Option<NonZeroXxx>>() == size_of::<xxx>()`; see `NonZeroXxx`
260c3739801SMiguel Ojeda //   documentation.
261c3739801SMiguel Ojeda // - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that `Option<NonZeroU8>`
262c3739801SMiguel Ojeda //   and `Option<NonZeroI8>` both have size 1. [1] [2] This is worded in a way
263c3739801SMiguel Ojeda //   that makes it unclear whether it's meant as a guarantee, but given the
264c3739801SMiguel Ojeda //   purpose of those types, it's virtually unthinkable that that would ever
265c3739801SMiguel Ojeda //   change. The only valid alignment for a 1-byte type is 1.
266c3739801SMiguel Ojeda //
267c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroU8.html:
268c3739801SMiguel Ojeda //
269c3739801SMiguel Ojeda //     `Option<NonZeroU8>` is guaranteed to be compatible with `u8`, including in FFI.
270c3739801SMiguel Ojeda //
271c3739801SMiguel Ojeda //     Thanks to the null pointer optimization, `NonZeroU8` and `Option<NonZeroU8>`
272c3739801SMiguel Ojeda //     are guaranteed to have the same size and alignment:
273c3739801SMiguel Ojeda //
274c3739801SMiguel Ojeda // [2] Per https://doc.rust-lang.org/1.81.0/std/num/type.NonZeroI8.html:
275c3739801SMiguel Ojeda //
276c3739801SMiguel Ojeda //     `Option<NonZeroI8>` is guaranteed to be compatible with `i8`, including in FFI.
277c3739801SMiguel Ojeda //
278c3739801SMiguel Ojeda //     Thanks to the null pointer optimization, `NonZeroI8` and `Option<NonZeroI8>`
279c3739801SMiguel Ojeda //     are guaranteed to have the same size and alignment:
280c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
281c3739801SMiguel Ojeda const _: () = unsafe {
282c3739801SMiguel Ojeda     unsafe_impl!(Option<NonZeroU8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
283c3739801SMiguel Ojeda     unsafe_impl!(Option<NonZeroI8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
284c3739801SMiguel Ojeda     assert_unaligned!(Option<NonZeroU8>, Option<NonZeroI8>);
285c3739801SMiguel Ojeda     unsafe_impl!(Option<NonZeroU16>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
286c3739801SMiguel Ojeda     unsafe_impl!(Option<NonZeroI16>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
287c3739801SMiguel Ojeda     unsafe_impl!(Option<NonZeroU32>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
288c3739801SMiguel Ojeda     unsafe_impl!(Option<NonZeroI32>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
289c3739801SMiguel Ojeda     unsafe_impl!(Option<NonZeroU64>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
290c3739801SMiguel Ojeda     unsafe_impl!(Option<NonZeroI64>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
291c3739801SMiguel Ojeda     unsafe_impl!(Option<NonZeroU128>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
292c3739801SMiguel Ojeda     unsafe_impl!(Option<NonZeroI128>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
293c3739801SMiguel Ojeda     unsafe_impl!(Option<NonZeroUsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
294c3739801SMiguel Ojeda     unsafe_impl!(Option<NonZeroIsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
295c3739801SMiguel Ojeda };
296c3739801SMiguel Ojeda 
297c3739801SMiguel Ojeda // SAFETY: While it's not fully documented, the consensus is that `Box<T>` does
298c3739801SMiguel Ojeda // not contain any `UnsafeCell`s for `T: Sized` [1]. This is not a complete
299c3739801SMiguel Ojeda // proof, but we are accepting this as a known risk per #1358.
300c3739801SMiguel Ojeda //
301c3739801SMiguel Ojeda // [1] https://github.com/rust-lang/unsafe-code-guidelines/issues/492
302c3739801SMiguel Ojeda #[cfg(feature = "alloc")]
303c3739801SMiguel Ojeda const _: () = unsafe {
304c3739801SMiguel Ojeda     unsafe_impl!(
305c3739801SMiguel Ojeda         #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
306c3739801SMiguel Ojeda         T: Sized => Immutable for Box<T>
307c3739801SMiguel Ojeda     )
308c3739801SMiguel Ojeda };
309c3739801SMiguel Ojeda 
310c3739801SMiguel Ojeda // SAFETY: The following types can be transmuted from `[0u8; size_of::<T>()]`. [1]
311c3739801SMiguel Ojeda //
312c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.89.0/core/option/index.html#representation:
313c3739801SMiguel Ojeda //
314c3739801SMiguel Ojeda //   Rust guarantees to optimize the following types `T` such that [`Option<T>`]
315c3739801SMiguel Ojeda //   has the same size and alignment as `T`. In some of these cases, Rust
316c3739801SMiguel Ojeda //   further guarantees that `transmute::<_, Option<T>>([0u8; size_of::<T>()])`
317c3739801SMiguel Ojeda //   is sound and produces `Option::<T>::None`. These cases are identified by
318c3739801SMiguel Ojeda //   the second column:
319c3739801SMiguel Ojeda //
320c3739801SMiguel Ojeda //   | `T`                               | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? |
321c3739801SMiguel Ojeda //   |-----------------------------------|-----------------------------------------------------------|
322c3739801SMiguel Ojeda //   | [`Box<U>`]                        | when `U: Sized`                                           |
323c3739801SMiguel Ojeda //   | `&U`                              | when `U: Sized`                                           |
324c3739801SMiguel Ojeda //   | `&mut U`                          | when `U: Sized`                                           |
325c3739801SMiguel Ojeda //   | [`ptr::NonNull<U>`]               | when `U: Sized`                                           |
326c3739801SMiguel Ojeda //   | `fn`, `extern "C" fn`[^extern_fn] | always                                                    |
327c3739801SMiguel Ojeda //
328c3739801SMiguel Ojeda //   [^extern_fn]: this remains true for `unsafe` variants, any argument/return
329c3739801SMiguel Ojeda //     types, and any other ABI: `[unsafe] extern "abi" fn` (_e.g._, `extern
330c3739801SMiguel Ojeda //     "system" fn`)
331c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
332c3739801SMiguel Ojeda const _: () = unsafe {
333c3739801SMiguel Ojeda     #[cfg(feature = "alloc")]
334c3739801SMiguel Ojeda     unsafe_impl!(
335c3739801SMiguel Ojeda         #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
336c3739801SMiguel Ojeda         T => TryFromBytes for Option<Box<T>>; |c| pointer::is_zeroed(c)
337c3739801SMiguel Ojeda     );
338c3739801SMiguel Ojeda     #[cfg(feature = "alloc")]
339c3739801SMiguel Ojeda     unsafe_impl!(
340c3739801SMiguel Ojeda         #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
341c3739801SMiguel Ojeda         T => FromZeros for Option<Box<T>>
342c3739801SMiguel Ojeda     );
343c3739801SMiguel Ojeda     unsafe_impl!(
344c3739801SMiguel Ojeda         T => TryFromBytes for Option<&'_ T>; |c| pointer::is_zeroed(c)
345c3739801SMiguel Ojeda     );
346c3739801SMiguel Ojeda     unsafe_impl!(T => FromZeros for Option<&'_ T>);
347c3739801SMiguel Ojeda     unsafe_impl!(
348c3739801SMiguel Ojeda             T => TryFromBytes for Option<&'_ mut T>; |c| pointer::is_zeroed(c)
349c3739801SMiguel Ojeda     );
350c3739801SMiguel Ojeda     unsafe_impl!(T => FromZeros for Option<&'_ mut T>);
351c3739801SMiguel Ojeda     unsafe_impl!(
352c3739801SMiguel Ojeda         T => TryFromBytes for Option<NonNull<T>>; |c| pointer::is_zeroed(c)
353c3739801SMiguel Ojeda     );
354c3739801SMiguel Ojeda     unsafe_impl!(T => FromZeros for Option<NonNull<T>>);
355c3739801SMiguel Ojeda     unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_fn!(...));
356c3739801SMiguel Ojeda     unsafe_impl_for_power_set!(
357c3739801SMiguel Ojeda         A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_fn!(...);
358c3739801SMiguel Ojeda         |c| pointer::is_zeroed(c)
359c3739801SMiguel Ojeda     );
360c3739801SMiguel Ojeda     unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_unsafe_fn!(...));
361c3739801SMiguel Ojeda     unsafe_impl_for_power_set!(
362c3739801SMiguel Ojeda         A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_unsafe_fn!(...);
363c3739801SMiguel Ojeda         |c| pointer::is_zeroed(c)
364c3739801SMiguel Ojeda     );
365c3739801SMiguel Ojeda     unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_extern_c_fn!(...));
366c3739801SMiguel Ojeda     unsafe_impl_for_power_set!(
367c3739801SMiguel Ojeda         A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_extern_c_fn!(...);
368c3739801SMiguel Ojeda         |c| pointer::is_zeroed(c)
369c3739801SMiguel Ojeda     );
370c3739801SMiguel Ojeda     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!(...));
371c3739801SMiguel Ojeda     unsafe_impl_for_power_set!(
372c3739801SMiguel Ojeda         A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_unsafe_extern_c_fn!(...);
373c3739801SMiguel Ojeda         |c| pointer::is_zeroed(c)
374c3739801SMiguel Ojeda     );
375c3739801SMiguel Ojeda };
376c3739801SMiguel Ojeda 
377c3739801SMiguel Ojeda // SAFETY: `[unsafe] [extern "C"] fn()` self-evidently do not contain
378c3739801SMiguel Ojeda // `UnsafeCell`s. This is not a proof, but we are accepting this as a known risk
379c3739801SMiguel Ojeda // per #1358.
380c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
381c3739801SMiguel Ojeda const _: () = unsafe {
382c3739801SMiguel Ojeda     unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_fn!(...));
383c3739801SMiguel Ojeda     unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_unsafe_fn!(...));
384c3739801SMiguel Ojeda     unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_extern_c_fn!(...));
385c3739801SMiguel Ojeda     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!(...));
386c3739801SMiguel Ojeda };
387c3739801SMiguel Ojeda 
388c3739801SMiguel Ojeda #[cfg(all(
389c3739801SMiguel Ojeda     not(no_zerocopy_target_has_atomics_1_60_0),
390c3739801SMiguel Ojeda     any(
391c3739801SMiguel Ojeda         target_has_atomic = "8",
392c3739801SMiguel Ojeda         target_has_atomic = "16",
393c3739801SMiguel Ojeda         target_has_atomic = "32",
394c3739801SMiguel Ojeda         target_has_atomic = "64",
395c3739801SMiguel Ojeda         target_has_atomic = "ptr"
396c3739801SMiguel Ojeda     )
397c3739801SMiguel Ojeda ))]
398c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(rust = "1.60.0")))]
399c3739801SMiguel Ojeda mod atomics {
400c3739801SMiguel Ojeda     use super::*;
401c3739801SMiguel Ojeda 
402c3739801SMiguel Ojeda     macro_rules! impl_traits_for_atomics {
403c3739801SMiguel Ojeda         ($($atomics:tt [$primitives:ty]),* $(,)?) => {
404c3739801SMiguel Ojeda             $(
405c3739801SMiguel Ojeda                 impl_known_layout!($atomics);
406c3739801SMiguel Ojeda                 impl_for_transmute_from!(=> FromZeros for $atomics [$primitives]);
407c3739801SMiguel Ojeda                 impl_for_transmute_from!(=> FromBytes for $atomics [$primitives]);
408c3739801SMiguel Ojeda                 impl_for_transmute_from!(=> TryFromBytes for $atomics [$primitives]);
409c3739801SMiguel Ojeda                 impl_for_transmute_from!(=> IntoBytes for $atomics [$primitives]);
410c3739801SMiguel Ojeda             )*
411c3739801SMiguel Ojeda         };
412c3739801SMiguel Ojeda     }
413c3739801SMiguel Ojeda 
414c3739801SMiguel Ojeda     /// Implements `TransmuteFrom` for `$atomic`, `$prim`, and
415c3739801SMiguel Ojeda     /// `UnsafeCell<$prim>`.
416c3739801SMiguel Ojeda     ///
417c3739801SMiguel Ojeda     /// # Safety
418c3739801SMiguel Ojeda     ///
419c3739801SMiguel Ojeda     /// `$atomic` must have the same size and bit validity as `$prim`.
420c3739801SMiguel Ojeda     macro_rules! unsafe_impl_transmute_from_for_atomic {
421c3739801SMiguel Ojeda         ($($($tyvar:ident)? => $atomic:ty [$prim:ty]),*) => {{
422c3739801SMiguel Ojeda             crate::util::macros::__unsafe();
423c3739801SMiguel Ojeda 
424c3739801SMiguel Ojeda             use crate::pointer::{SizeEq, TransmuteFrom, invariant::Valid};
425c3739801SMiguel Ojeda 
426c3739801SMiguel Ojeda             $(
427c3739801SMiguel Ojeda                 // SAFETY: The caller promised that `$atomic` and `$prim` have
428c3739801SMiguel Ojeda                 // the same size and bit validity.
429c3739801SMiguel Ojeda                 unsafe impl<$($tyvar)?> TransmuteFrom<$atomic, Valid, Valid> for $prim {}
430c3739801SMiguel Ojeda                 // SAFETY: The caller promised that `$atomic` and `$prim` have
431c3739801SMiguel Ojeda                 // the same size and bit validity.
432c3739801SMiguel Ojeda                 unsafe impl<$($tyvar)?> TransmuteFrom<$prim, Valid, Valid> for $atomic {}
433c3739801SMiguel Ojeda 
434c3739801SMiguel Ojeda                 impl<$($tyvar)?> SizeEq<ReadOnly<$atomic>> for ReadOnly<$prim> {
435c3739801SMiguel Ojeda                     type CastFrom = $crate::pointer::cast::CastSizedExact;
436c3739801SMiguel Ojeda                 }
437c3739801SMiguel Ojeda 
438c3739801SMiguel Ojeda                 // SAFETY: The caller promised that `$atomic` and `$prim` have
439c3739801SMiguel Ojeda                 // the same bit validity. `UnsafeCell<T>` has the same bit
440c3739801SMiguel Ojeda                 // validity as `T` [1].
441c3739801SMiguel Ojeda                 //
442c3739801SMiguel Ojeda                 // [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.UnsafeCell.html#memory-layout:
443c3739801SMiguel Ojeda                 //
444c3739801SMiguel Ojeda                 //   `UnsafeCell<T>` has the same in-memory representation as
445c3739801SMiguel Ojeda                 //   its inner type `T`. A consequence of this guarantee is that
446c3739801SMiguel Ojeda                 //   it is possible to convert between `T` and `UnsafeCell<T>`.
447c3739801SMiguel Ojeda                 unsafe impl<$($tyvar)?> TransmuteFrom<$atomic, Valid, Valid> for core::cell::UnsafeCell<$prim> {}
448c3739801SMiguel Ojeda                 // SAFETY: See previous safety comment.
449c3739801SMiguel Ojeda                 unsafe impl<$($tyvar)?> TransmuteFrom<core::cell::UnsafeCell<$prim>, Valid, Valid> for $atomic {}
450c3739801SMiguel Ojeda             )*
451c3739801SMiguel Ojeda         }};
452c3739801SMiguel Ojeda     }
453c3739801SMiguel Ojeda 
454c3739801SMiguel Ojeda     #[cfg(target_has_atomic = "8")]
455c3739801SMiguel Ojeda     #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "8")))]
456c3739801SMiguel Ojeda     mod atomic_8 {
457c3739801SMiguel Ojeda         use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
458c3739801SMiguel Ojeda 
459c3739801SMiguel Ojeda         use super::*;
460c3739801SMiguel Ojeda 
461c3739801SMiguel Ojeda         impl_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]);
462c3739801SMiguel Ojeda 
463c3739801SMiguel Ojeda         impl_known_layout!(AtomicBool);
464c3739801SMiguel Ojeda         impl_for_transmute_from!(=> FromZeros for AtomicBool [bool]);
465c3739801SMiguel Ojeda         impl_for_transmute_from!(=> TryFromBytes for AtomicBool [bool]);
466c3739801SMiguel Ojeda         impl_for_transmute_from!(=> IntoBytes for AtomicBool [bool]);
467c3739801SMiguel Ojeda 
468c3739801SMiguel Ojeda         // SAFETY: Per [1], `AtomicBool`, `AtomicU8`, and `AtomicI8` have the
469c3739801SMiguel Ojeda         // same size as `bool`, `u8`, and `i8` respectively. Since a type's
470c3739801SMiguel Ojeda         // alignment cannot be smaller than 1 [2], and since its alignment
471c3739801SMiguel Ojeda         // cannot be greater than its size [3], the only possible value for the
472c3739801SMiguel Ojeda         // alignment is 1. Thus, it is sound to implement `Unaligned`.
473c3739801SMiguel Ojeda         //
474c3739801SMiguel Ojeda         // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU8.html:
475c3739801SMiguel Ojeda         //
476c3739801SMiguel Ojeda         //   This type has the same size, alignment, and bit validity as the
477c3739801SMiguel Ojeda         //   underlying integer type
478c3739801SMiguel Ojeda         //
479c3739801SMiguel Ojeda         // [2] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment:
480c3739801SMiguel Ojeda         //
481c3739801SMiguel Ojeda         //     Alignment is measured in bytes, and must be at least 1.
482c3739801SMiguel Ojeda         //
483c3739801SMiguel Ojeda         // [3] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#size-and-alignment:
484c3739801SMiguel Ojeda         //
485c3739801SMiguel Ojeda         //     The size of a value is always a multiple of its alignment.
486c3739801SMiguel Ojeda         #[allow(clippy::multiple_unsafe_ops_per_block)]
487c3739801SMiguel Ojeda         const _: () = unsafe {
488c3739801SMiguel Ojeda             unsafe_impl!(AtomicBool: Unaligned);
489c3739801SMiguel Ojeda             unsafe_impl!(AtomicU8: Unaligned);
490c3739801SMiguel Ojeda             unsafe_impl!(AtomicI8: Unaligned);
491c3739801SMiguel Ojeda             assert_unaligned!(AtomicBool, AtomicU8, AtomicI8);
492c3739801SMiguel Ojeda         };
493c3739801SMiguel Ojeda 
494c3739801SMiguel Ojeda         // SAFETY: `AtomicU8`, `AtomicI8`, and `AtomicBool` have the same size
495c3739801SMiguel Ojeda         // and bit validity as `u8`, `i8`, and `bool` respectively [1][2][3].
496c3739801SMiguel Ojeda         //
497c3739801SMiguel Ojeda         // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU8.html:
498c3739801SMiguel Ojeda         //
499c3739801SMiguel Ojeda         //   This type has the same size, alignment, and bit validity as the
500c3739801SMiguel Ojeda         //   underlying integer type, `u8`.
501c3739801SMiguel Ojeda         //
502c3739801SMiguel Ojeda         // [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicI8.html:
503c3739801SMiguel Ojeda         //
504c3739801SMiguel Ojeda         //   This type has the same size, alignment, and bit validity as the
505c3739801SMiguel Ojeda         //   underlying integer type, `i8`.
506c3739801SMiguel Ojeda         //
507c3739801SMiguel Ojeda         // [3] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicBool.html:
508c3739801SMiguel Ojeda         //
509c3739801SMiguel Ojeda         //   This type has the same size, alignment, and bit validity a `bool`.
510c3739801SMiguel Ojeda         #[allow(clippy::multiple_unsafe_ops_per_block)]
511c3739801SMiguel Ojeda         const _: () = unsafe {
512c3739801SMiguel Ojeda             unsafe_impl_transmute_from_for_atomic!(
513c3739801SMiguel Ojeda                 => AtomicU8 [u8],
514c3739801SMiguel Ojeda                 => AtomicI8 [i8],
515c3739801SMiguel Ojeda                 => AtomicBool [bool]
516c3739801SMiguel Ojeda             )
517c3739801SMiguel Ojeda         };
518c3739801SMiguel Ojeda     }
519c3739801SMiguel Ojeda 
520c3739801SMiguel Ojeda     #[cfg(target_has_atomic = "16")]
521c3739801SMiguel Ojeda     #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "16")))]
522c3739801SMiguel Ojeda     mod atomic_16 {
523c3739801SMiguel Ojeda         use core::sync::atomic::{AtomicI16, AtomicU16};
524c3739801SMiguel Ojeda 
525c3739801SMiguel Ojeda         use super::*;
526c3739801SMiguel Ojeda 
527c3739801SMiguel Ojeda         impl_traits_for_atomics!(AtomicU16[u16], AtomicI16[i16]);
528c3739801SMiguel Ojeda 
529c3739801SMiguel Ojeda         // SAFETY: `AtomicU16` and `AtomicI16` have the same size and bit
530c3739801SMiguel Ojeda         // validity as `u16` and `i16` respectively [1][2].
531c3739801SMiguel Ojeda         //
532c3739801SMiguel Ojeda         // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU16.html:
533c3739801SMiguel Ojeda         //
534c3739801SMiguel Ojeda         //   This type has the same size and bit validity as the underlying
535c3739801SMiguel Ojeda         //   integer type, `u16`.
536c3739801SMiguel Ojeda         //
537c3739801SMiguel Ojeda         // [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicI16.html:
538c3739801SMiguel Ojeda         //
539c3739801SMiguel Ojeda         //   This type has the same size and bit validity as the underlying
540c3739801SMiguel Ojeda         //   integer type, `i16`.
541c3739801SMiguel Ojeda         #[allow(clippy::multiple_unsafe_ops_per_block)]
542c3739801SMiguel Ojeda         const _: () = unsafe {
543c3739801SMiguel Ojeda             unsafe_impl_transmute_from_for_atomic!(=> AtomicU16 [u16], => AtomicI16 [i16])
544c3739801SMiguel Ojeda         };
545c3739801SMiguel Ojeda     }
546c3739801SMiguel Ojeda 
547c3739801SMiguel Ojeda     #[cfg(target_has_atomic = "32")]
548c3739801SMiguel Ojeda     #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "32")))]
549c3739801SMiguel Ojeda     mod atomic_32 {
550c3739801SMiguel Ojeda         use core::sync::atomic::{AtomicI32, AtomicU32};
551c3739801SMiguel Ojeda 
552c3739801SMiguel Ojeda         use super::*;
553c3739801SMiguel Ojeda 
554c3739801SMiguel Ojeda         impl_traits_for_atomics!(AtomicU32[u32], AtomicI32[i32]);
555c3739801SMiguel Ojeda 
556c3739801SMiguel Ojeda         // SAFETY: `AtomicU32` and `AtomicI32` have the same size and bit
557c3739801SMiguel Ojeda         // validity as `u32` and `i32` respectively [1][2].
558c3739801SMiguel Ojeda         //
559c3739801SMiguel Ojeda         // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU32.html:
560c3739801SMiguel Ojeda         //
561c3739801SMiguel Ojeda         //   This type has the same size and bit validity as the underlying
562c3739801SMiguel Ojeda         //   integer type, `u32`.
563c3739801SMiguel Ojeda         //
564c3739801SMiguel Ojeda         // [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicI32.html:
565c3739801SMiguel Ojeda         //
566c3739801SMiguel Ojeda         //   This type has the same size and bit validity as the underlying
567c3739801SMiguel Ojeda         //   integer type, `i32`.
568c3739801SMiguel Ojeda         #[allow(clippy::multiple_unsafe_ops_per_block)]
569c3739801SMiguel Ojeda         const _: () = unsafe {
570c3739801SMiguel Ojeda             unsafe_impl_transmute_from_for_atomic!(=> AtomicU32 [u32], => AtomicI32 [i32])
571c3739801SMiguel Ojeda         };
572c3739801SMiguel Ojeda     }
573c3739801SMiguel Ojeda 
574c3739801SMiguel Ojeda     #[cfg(target_has_atomic = "64")]
575c3739801SMiguel Ojeda     #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "64")))]
576c3739801SMiguel Ojeda     mod atomic_64 {
577c3739801SMiguel Ojeda         use core::sync::atomic::{AtomicI64, AtomicU64};
578c3739801SMiguel Ojeda 
579c3739801SMiguel Ojeda         use super::*;
580c3739801SMiguel Ojeda 
581c3739801SMiguel Ojeda         impl_traits_for_atomics!(AtomicU64[u64], AtomicI64[i64]);
582c3739801SMiguel Ojeda 
583c3739801SMiguel Ojeda         // SAFETY: `AtomicU64` and `AtomicI64` have the same size and bit
584c3739801SMiguel Ojeda         // validity as `u64` and `i64` respectively [1][2].
585c3739801SMiguel Ojeda         //
586c3739801SMiguel Ojeda         // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicU64.html:
587c3739801SMiguel Ojeda         //
588c3739801SMiguel Ojeda         //   This type has the same size and bit validity as the underlying
589c3739801SMiguel Ojeda         //   integer type, `u64`.
590c3739801SMiguel Ojeda         //
591c3739801SMiguel Ojeda         // [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicI64.html:
592c3739801SMiguel Ojeda         //
593c3739801SMiguel Ojeda         //   This type has the same size and bit validity as the underlying
594c3739801SMiguel Ojeda         //   integer type, `i64`.
595c3739801SMiguel Ojeda         #[allow(clippy::multiple_unsafe_ops_per_block)]
596c3739801SMiguel Ojeda         const _: () = unsafe {
597c3739801SMiguel Ojeda             unsafe_impl_transmute_from_for_atomic!(=> AtomicU64 [u64], => AtomicI64 [i64])
598c3739801SMiguel Ojeda         };
599c3739801SMiguel Ojeda     }
600c3739801SMiguel Ojeda 
601c3739801SMiguel Ojeda     #[cfg(target_has_atomic = "ptr")]
602c3739801SMiguel Ojeda     #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "ptr")))]
603c3739801SMiguel Ojeda     mod atomic_ptr {
604c3739801SMiguel Ojeda         use core::sync::atomic::{AtomicIsize, AtomicPtr, AtomicUsize};
605c3739801SMiguel Ojeda 
606c3739801SMiguel Ojeda         use super::*;
607c3739801SMiguel Ojeda 
608c3739801SMiguel Ojeda         impl_traits_for_atomics!(AtomicUsize[usize], AtomicIsize[isize]);
609c3739801SMiguel Ojeda 
610c3739801SMiguel Ojeda         // FIXME(#170): Implement `FromBytes` and `IntoBytes` once we implement
611c3739801SMiguel Ojeda         // those traits for `*mut T`.
612c3739801SMiguel Ojeda         impl_known_layout!(T => AtomicPtr<T>);
613c3739801SMiguel Ojeda         impl_for_transmute_from!(T => TryFromBytes for AtomicPtr<T> [*mut T]);
614c3739801SMiguel Ojeda         impl_for_transmute_from!(T => FromZeros for AtomicPtr<T> [*mut T]);
615c3739801SMiguel Ojeda 
616c3739801SMiguel Ojeda         // SAFETY: `AtomicUsize` and `AtomicIsize` have the same size and bit
617c3739801SMiguel Ojeda         // validity as `usize` and `isize` respectively [1][2].
618c3739801SMiguel Ojeda         //
619c3739801SMiguel Ojeda         // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicUsize.html:
620c3739801SMiguel Ojeda         //
621c3739801SMiguel Ojeda         //   This type has the same size and bit validity as the underlying
622c3739801SMiguel Ojeda         //   integer type, `usize`.
623c3739801SMiguel Ojeda         //
624c3739801SMiguel Ojeda         // [2] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicIsize.html:
625c3739801SMiguel Ojeda         //
626c3739801SMiguel Ojeda         //   This type has the same size and bit validity as the underlying
627c3739801SMiguel Ojeda         //   integer type, `isize`.
628c3739801SMiguel Ojeda         #[allow(clippy::multiple_unsafe_ops_per_block)]
629c3739801SMiguel Ojeda         const _: () = unsafe {
630c3739801SMiguel Ojeda             unsafe_impl_transmute_from_for_atomic!(=> AtomicUsize [usize], => AtomicIsize [isize])
631c3739801SMiguel Ojeda         };
632c3739801SMiguel Ojeda 
633c3739801SMiguel Ojeda         // SAFETY: Per
634c3739801SMiguel Ojeda         // https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicPtr.html:
635c3739801SMiguel Ojeda         //
636c3739801SMiguel Ojeda         //   This type has the same size and bit validity as a `*mut T`.
637c3739801SMiguel Ojeda         #[allow(clippy::multiple_unsafe_ops_per_block)]
638c3739801SMiguel Ojeda         const _: () = unsafe { unsafe_impl_transmute_from_for_atomic!(T => AtomicPtr<T> [*mut T]) };
639c3739801SMiguel Ojeda     }
640c3739801SMiguel Ojeda }
641c3739801SMiguel Ojeda 
642c3739801SMiguel Ojeda // SAFETY: Per reference [1]: "For all T, the following are guaranteed:
643c3739801SMiguel Ojeda // size_of::<PhantomData<T>>() == 0 align_of::<PhantomData<T>>() == 1". This
644c3739801SMiguel Ojeda // gives:
645c3739801SMiguel Ojeda // - `Immutable`: `PhantomData` has no fields.
646c3739801SMiguel Ojeda // - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: There is only
647c3739801SMiguel Ojeda //   one possible sequence of 0 bytes, and `PhantomData` is inhabited.
648c3739801SMiguel Ojeda // - `IntoBytes`: Since `PhantomData` has size 0, it contains no padding bytes.
649c3739801SMiguel Ojeda // - `Unaligned`: Per the preceding reference, `PhantomData` has alignment 1.
650c3739801SMiguel Ojeda //
651c3739801SMiguel Ojeda // [1] https://doc.rust-lang.org/1.81.0/std/marker/struct.PhantomData.html#layout-1
652c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
653c3739801SMiguel Ojeda const _: () = unsafe {
654c3739801SMiguel Ojeda     unsafe_impl!(T: ?Sized => Immutable for PhantomData<T>);
655c3739801SMiguel Ojeda     unsafe_impl!(T: ?Sized => TryFromBytes for PhantomData<T>);
656c3739801SMiguel Ojeda     unsafe_impl!(T: ?Sized => FromZeros for PhantomData<T>);
657c3739801SMiguel Ojeda     unsafe_impl!(T: ?Sized => FromBytes for PhantomData<T>);
658c3739801SMiguel Ojeda     unsafe_impl!(T: ?Sized => IntoBytes for PhantomData<T>);
659c3739801SMiguel Ojeda     unsafe_impl!(T: ?Sized => Unaligned for PhantomData<T>);
660c3739801SMiguel Ojeda     assert_unaligned!(PhantomData<()>, PhantomData<u8>, PhantomData<u64>);
661c3739801SMiguel Ojeda };
662c3739801SMiguel Ojeda 
663c3739801SMiguel Ojeda impl_for_transmute_from!(T: TryFromBytes => TryFromBytes for Wrapping<T>[T]);
664c3739801SMiguel Ojeda impl_for_transmute_from!(T: FromZeros => FromZeros for Wrapping<T>[T]);
665c3739801SMiguel Ojeda impl_for_transmute_from!(T: FromBytes => FromBytes for Wrapping<T>[T]);
666c3739801SMiguel Ojeda impl_for_transmute_from!(T: IntoBytes => IntoBytes for Wrapping<T>[T]);
667c3739801SMiguel Ojeda assert_unaligned!(Wrapping<()>, Wrapping<u8>);
668c3739801SMiguel Ojeda 
669c3739801SMiguel Ojeda // SAFETY: Per [1], `Wrapping<T>` has the same layout as `T`. Since its single
670c3739801SMiguel Ojeda // field (of type `T`) is public, it would be a breaking change to add or remove
671c3739801SMiguel Ojeda // fields. Thus, we know that `Wrapping<T>` contains a `T` (as opposed to just
672c3739801SMiguel Ojeda // having the same size and alignment as `T`) with no pre- or post-padding.
673c3739801SMiguel Ojeda // Thus, `Wrapping<T>` must have `UnsafeCell`s covering the same byte ranges as
674c3739801SMiguel Ojeda // `Inner = T`.
675c3739801SMiguel Ojeda //
676c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1:
677c3739801SMiguel Ojeda //
678c3739801SMiguel Ojeda //   `Wrapping<T>` is guaranteed to have the same layout and ABI as `T`
679c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(T: Immutable => Immutable for Wrapping<T>) };
680c3739801SMiguel Ojeda 
681c3739801SMiguel Ojeda // SAFETY: Per [1] in the preceding safety comment, `Wrapping<T>` has the same
682c3739801SMiguel Ojeda // alignment as `T`.
683c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(T: Unaligned => Unaligned for Wrapping<T>) };
684c3739801SMiguel Ojeda 
685c3739801SMiguel Ojeda // SAFETY: `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`:
686c3739801SMiguel Ojeda // `MaybeUninit<T>` has no restrictions on its contents.
687c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
688c3739801SMiguel Ojeda const _: () = unsafe {
689c3739801SMiguel Ojeda     unsafe_impl!(T => TryFromBytes for CoreMaybeUninit<T>);
690c3739801SMiguel Ojeda     unsafe_impl!(T => FromZeros for CoreMaybeUninit<T>);
691c3739801SMiguel Ojeda     unsafe_impl!(T => FromBytes for CoreMaybeUninit<T>);
692c3739801SMiguel Ojeda };
693c3739801SMiguel Ojeda 
694c3739801SMiguel Ojeda // SAFETY: `MaybeUninit<T>` has `UnsafeCell`s covering the same byte ranges as
695c3739801SMiguel Ojeda // `Inner = T`. This is not explicitly documented, but it can be inferred. Per
696c3739801SMiguel Ojeda // [1], `MaybeUninit<T>` has the same size as `T`. Further, note the signature
697c3739801SMiguel Ojeda // of `MaybeUninit::assume_init_ref` [2]:
698c3739801SMiguel Ojeda //
699c3739801SMiguel Ojeda //   pub unsafe fn assume_init_ref(&self) -> &T
700c3739801SMiguel Ojeda //
701c3739801SMiguel Ojeda // If the argument `&MaybeUninit<T>` and the returned `&T` had `UnsafeCell`s at
702c3739801SMiguel Ojeda // different offsets, this would be unsound. Its existence is proof that this is
703c3739801SMiguel Ojeda // not the case.
704c3739801SMiguel Ojeda //
705c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1:
706c3739801SMiguel Ojeda //
707c3739801SMiguel Ojeda // `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as
708c3739801SMiguel Ojeda // `T`.
709c3739801SMiguel Ojeda //
710c3739801SMiguel Ojeda // [2] https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#method.assume_init_ref
711c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(T: Immutable => Immutable for CoreMaybeUninit<T>) };
712c3739801SMiguel Ojeda 
713c3739801SMiguel Ojeda // SAFETY: Per [1] in the preceding safety comment, `MaybeUninit<T>` has the
714c3739801SMiguel Ojeda // same alignment as `T`.
715c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(T: Unaligned => Unaligned for CoreMaybeUninit<T>) };
716c3739801SMiguel Ojeda assert_unaligned!(CoreMaybeUninit<()>, CoreMaybeUninit<u8>);
717c3739801SMiguel Ojeda 
718c3739801SMiguel Ojeda // SAFETY: `ManuallyDrop<T>` has the same layout as `T` [1]. This strongly
719c3739801SMiguel Ojeda // implies, but does not guarantee, that it contains `UnsafeCell`s covering the
720c3739801SMiguel Ojeda // same byte ranges as in `T`. However, it also implements `Defer<Target = T>`
721c3739801SMiguel Ojeda // [2], which provides the ability to convert `&ManuallyDrop<T> -> &T`. This,
722c3739801SMiguel Ojeda // combined with having the same size as `T`, implies that `ManuallyDrop<T>`
723c3739801SMiguel Ojeda // exactly contains a `T` with the same fields and `UnsafeCell`s covering the
724c3739801SMiguel Ojeda // same byte ranges, or else the `Deref` impl would permit safe code to obtain
725c3739801SMiguel Ojeda // different shared references to the same region of memory with different
726c3739801SMiguel Ojeda // `UnsafeCell` coverage, which would in turn permit interior mutation that
727c3739801SMiguel Ojeda // would violate the invariants of a shared reference.
728c3739801SMiguel Ojeda //
729c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html:
730c3739801SMiguel Ojeda //
731c3739801SMiguel Ojeda //   `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as
732c3739801SMiguel Ojeda //   `T`
733c3739801SMiguel Ojeda //
734c3739801SMiguel Ojeda // [2] https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html#impl-Deref-for-ManuallyDrop%3CT%3E
735c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(T: ?Sized + Immutable => Immutable for ManuallyDrop<T>) };
736c3739801SMiguel Ojeda 
737c3739801SMiguel Ojeda impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop<T>[T]);
738c3739801SMiguel Ojeda impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop<T>[T]);
739c3739801SMiguel Ojeda impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>[T]);
740c3739801SMiguel Ojeda impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop<T>[T]);
741c3739801SMiguel Ojeda // SAFETY: `ManuallyDrop<T>` has the same layout as `T` [1], and thus has the
742c3739801SMiguel Ojeda // same alignment as `T`.
743c3739801SMiguel Ojeda //
744c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html:
745c3739801SMiguel Ojeda //
746c3739801SMiguel Ojeda //   `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as
747c3739801SMiguel Ojeda //   `T`
748c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop<T>) };
749c3739801SMiguel Ojeda assert_unaligned!(ManuallyDrop<()>, ManuallyDrop<u8>);
750c3739801SMiguel Ojeda 
751c3739801SMiguel Ojeda const _: () = {
752c3739801SMiguel Ojeda     #[allow(
753c3739801SMiguel Ojeda         non_camel_case_types,
754c3739801SMiguel Ojeda         missing_copy_implementations,
755c3739801SMiguel Ojeda         missing_debug_implementations,
756c3739801SMiguel Ojeda         missing_docs
757c3739801SMiguel Ojeda     )]
758c3739801SMiguel Ojeda     pub enum value {}
759c3739801SMiguel Ojeda 
760c3739801SMiguel Ojeda     // SAFETY: See safety comment on `ProjectToTag`.
761c3739801SMiguel Ojeda     unsafe impl<T: ?Sized> HasTag for ManuallyDrop<T> {
762c3739801SMiguel Ojeda         #[inline]
763c3739801SMiguel Ojeda         fn only_derive_is_allowed_to_implement_this_trait()
764c3739801SMiguel Ojeda         where
765c3739801SMiguel Ojeda             Self: Sized,
766c3739801SMiguel Ojeda         {
767c3739801SMiguel Ojeda         }
768c3739801SMiguel Ojeda 
769c3739801SMiguel Ojeda         type Tag = ();
770c3739801SMiguel Ojeda 
771c3739801SMiguel Ojeda         // SAFETY: It is trivially sound to project any pointer to a pointer to
772c3739801SMiguel Ojeda         // a type of size zero and alignment 1 (which `()` is [1]). Such a
773c3739801SMiguel Ojeda         // pointer will trivially satisfy its aliasing and validity requirements
774c3739801SMiguel Ojeda         // (since it has a zero-sized referent), and its alignment requirement
775c3739801SMiguel Ojeda         // (since it is aligned to 1).
776c3739801SMiguel Ojeda         //
777c3739801SMiguel Ojeda         // [1] Per https://doc.rust-lang.org/1.92.0/reference/type-layout.html#r-layout.tuple.unit:
778c3739801SMiguel Ojeda         //
779c3739801SMiguel Ojeda         //     [T]he unit tuple (`()`)... is guaranteed as a zero-sized type to
780c3739801SMiguel Ojeda         //     have a size of 0 and an alignment of 1.
781c3739801SMiguel Ojeda         type ProjectToTag = crate::pointer::cast::CastToUnit;
782c3739801SMiguel Ojeda     }
783c3739801SMiguel Ojeda 
784c3739801SMiguel Ojeda     // SAFETY: `ManuallyDrop<T>` has a field of type `T` at offset `0` without
785c3739801SMiguel Ojeda     // any safety invariants beyond those of `T`.  Its existence is not
786c3739801SMiguel Ojeda     // explicitly documented, but it can be inferred; per [1] `ManuallyDrop<T>`
787c3739801SMiguel Ojeda     // has the same size and bit validity as `T`. This field is not literally
788c3739801SMiguel Ojeda     // public, but is effectively so; the field can be transparently:
789c3739801SMiguel Ojeda     //
790c3739801SMiguel Ojeda     //  - initialized via `ManuallyDrop::new`
791c3739801SMiguel Ojeda     //  - moved via `ManuallyDrop::into_inner`
792c3739801SMiguel Ojeda     //  - referenced via `ManuallyDrop::deref`
793c3739801SMiguel Ojeda     //  - exclusively referenced via `ManuallyDrop::deref_mut`
794c3739801SMiguel Ojeda     //
795c3739801SMiguel Ojeda     // We call this field `value`, both because that is both the name of this
796c3739801SMiguel Ojeda     // private field, and because it is the name it is referred to in the public
797c3739801SMiguel Ojeda     // documentation of `ManuallyDrop::new`, `ManuallyDrop::into_inner`,
798c3739801SMiguel Ojeda     // `ManuallyDrop::take` and `ManuallyDrop::drop`.
799c3739801SMiguel Ojeda     unsafe impl<T: ?Sized>
800c3739801SMiguel Ojeda         HasField<value, { crate::STRUCT_VARIANT_ID }, { crate::ident_id!(value) }>
801c3739801SMiguel Ojeda         for ManuallyDrop<T>
802c3739801SMiguel Ojeda     {
803c3739801SMiguel Ojeda         #[inline]
804c3739801SMiguel Ojeda         fn only_derive_is_allowed_to_implement_this_trait()
805c3739801SMiguel Ojeda         where
806c3739801SMiguel Ojeda             Self: Sized,
807c3739801SMiguel Ojeda         {
808c3739801SMiguel Ojeda         }
809c3739801SMiguel Ojeda 
810c3739801SMiguel Ojeda         type Type = T;
811c3739801SMiguel Ojeda 
812c3739801SMiguel Ojeda         #[inline(always)]
813c3739801SMiguel Ojeda         fn project(slf: PtrInner<'_, Self>) -> *mut T {
814c3739801SMiguel Ojeda             // SAFETY: `ManuallyDrop<T>` has the same layout and bit validity as
815c3739801SMiguel Ojeda             // `T` [1].
816c3739801SMiguel Ojeda             //
817c3739801SMiguel Ojeda             // [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html:
818c3739801SMiguel Ojeda             //
819c3739801SMiguel Ojeda             //   `ManuallyDrop<T>` is guaranteed to have the same layout and bit
820c3739801SMiguel Ojeda             //   validity as `T`
821c3739801SMiguel Ojeda             #[allow(clippy::as_conversions)]
822c3739801SMiguel Ojeda             return slf.as_ptr() as *mut T;
823c3739801SMiguel Ojeda         }
824c3739801SMiguel Ojeda     }
825c3739801SMiguel Ojeda };
826c3739801SMiguel Ojeda 
827c3739801SMiguel Ojeda impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for Cell<T>[T]);
828c3739801SMiguel Ojeda impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for Cell<T>[T]);
829c3739801SMiguel Ojeda impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for Cell<T>[T]);
830c3739801SMiguel Ojeda impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for Cell<T>[T]);
831c3739801SMiguel Ojeda // SAFETY: `Cell<T>` has the same in-memory representation as `T` [1], and thus
832c3739801SMiguel Ojeda // has the same alignment as `T`.
833c3739801SMiguel Ojeda //
834c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.Cell.html#memory-layout:
835c3739801SMiguel Ojeda //
836c3739801SMiguel Ojeda //   `Cell<T>` has the same in-memory representation as its inner type `T`.
837c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(T: ?Sized + Unaligned => Unaligned for Cell<T>) };
838c3739801SMiguel Ojeda 
839c3739801SMiguel Ojeda impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>[T]);
840c3739801SMiguel Ojeda impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>[T]);
841c3739801SMiguel Ojeda impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>[T]);
842c3739801SMiguel Ojeda // SAFETY: `UnsafeCell<T>` has the same in-memory representation as `T` [1], and
843c3739801SMiguel Ojeda // thus has the same alignment as `T`.
844c3739801SMiguel Ojeda //
845c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout:
846c3739801SMiguel Ojeda //
847c3739801SMiguel Ojeda //   `UnsafeCell<T>` has the same in-memory representation as its inner type
848c3739801SMiguel Ojeda //   `T`.
849c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(T: ?Sized + Unaligned => Unaligned for UnsafeCell<T>) };
850c3739801SMiguel Ojeda assert_unaligned!(UnsafeCell<()>, UnsafeCell<u8>);
851c3739801SMiguel Ojeda 
852c3739801SMiguel Ojeda // SAFETY: See safety comment in `is_bit_valid` impl.
853c3739801SMiguel Ojeda unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
854c3739801SMiguel Ojeda     #[allow(clippy::missing_inline_in_public_items)]
855c3739801SMiguel Ojeda     fn only_derive_is_allowed_to_implement_this_trait()
856c3739801SMiguel Ojeda     where
857c3739801SMiguel Ojeda         Self: Sized,
858c3739801SMiguel Ojeda     {
859c3739801SMiguel Ojeda     }
860c3739801SMiguel Ojeda 
861c3739801SMiguel Ojeda     #[inline(always)]
862c3739801SMiguel Ojeda     fn is_bit_valid<A>(candidate: Maybe<'_, Self, A>) -> bool
863c3739801SMiguel Ojeda     where
864c3739801SMiguel Ojeda         A: invariant::Alignment,
865c3739801SMiguel Ojeda     {
866c3739801SMiguel Ojeda         T::is_bit_valid(candidate.transmute::<_, _, BecauseImmutable>())
867c3739801SMiguel Ojeda     }
868c3739801SMiguel Ojeda }
869c3739801SMiguel Ojeda 
870c3739801SMiguel Ojeda // SAFETY: Per the reference [1]:
871c3739801SMiguel Ojeda //
872c3739801SMiguel Ojeda //   An array of `[T; N]` has a size of `size_of::<T>() * N` and the same
873c3739801SMiguel Ojeda //   alignment of `T`. Arrays are laid out so that the zero-based `nth` element
874c3739801SMiguel Ojeda //   of the array is offset from the start of the array by `n * size_of::<T>()`
875c3739801SMiguel Ojeda //   bytes.
876c3739801SMiguel Ojeda //
877c3739801SMiguel Ojeda //   ...
878c3739801SMiguel Ojeda //
879c3739801SMiguel Ojeda //   Slices have the same layout as the section of the array they slice.
880c3739801SMiguel Ojeda //
881c3739801SMiguel Ojeda // In other words, the layout of a `[T]` or `[T; N]` is a sequence of `T`s laid
882c3739801SMiguel Ojeda // out back-to-back with no bytes in between. Therefore, `[T]` or `[T; N]` are
883c3739801SMiguel Ojeda // `Immutable`, `TryFromBytes`, `FromZeros`, `FromBytes`, and `IntoBytes` if `T`
884c3739801SMiguel Ojeda // is (respectively). Furthermore, since an array/slice has "the same alignment
885c3739801SMiguel Ojeda // of `T`", `[T]` and `[T; N]` are `Unaligned` if `T` is.
886c3739801SMiguel Ojeda //
887c3739801SMiguel Ojeda // Note that we don't `assert_unaligned!` for slice types because
888c3739801SMiguel Ojeda // `assert_unaligned!` uses `align_of`, which only works for `Sized` types.
889c3739801SMiguel Ojeda //
890c3739801SMiguel Ojeda // [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#array-layout
891c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
892c3739801SMiguel Ojeda const _: () = unsafe {
893c3739801SMiguel Ojeda     unsafe_impl!(const N: usize, T: Immutable => Immutable for [T; N]);
894c3739801SMiguel Ojeda     unsafe_impl!(const N: usize, T: TryFromBytes => TryFromBytes for [T; N]; |c| {
895c3739801SMiguel Ojeda         let c: Ptr<'_, [ReadOnly<T>; N], _> = c.cast::<_, crate::pointer::cast::CastSized, _>();
896c3739801SMiguel Ojeda         let c: Ptr<'_, [ReadOnly<T>], _> = c.as_slice();
897c3739801SMiguel Ojeda         let c: Ptr<'_, ReadOnly<[T]>, _> = c.cast::<_, crate::pointer::cast::CastUnsized, _>();
898c3739801SMiguel Ojeda 
899c3739801SMiguel Ojeda         // Note that this call may panic, but it would still be sound even if it
900c3739801SMiguel Ojeda         // did. `is_bit_valid` does not promise that it will not panic (in fact,
901c3739801SMiguel Ojeda         // it explicitly warns that it's a possibility), and we have not
902c3739801SMiguel Ojeda         // violated any safety invariants that we must fix before returning.
903c3739801SMiguel Ojeda         <[T] as TryFromBytes>::is_bit_valid(c)
904c3739801SMiguel Ojeda     });
905c3739801SMiguel Ojeda     unsafe_impl!(const N: usize, T: FromZeros => FromZeros for [T; N]);
906c3739801SMiguel Ojeda     unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]);
907c3739801SMiguel Ojeda     unsafe_impl!(const N: usize, T: IntoBytes => IntoBytes for [T; N]);
908c3739801SMiguel Ojeda     unsafe_impl!(const N: usize, T: Unaligned => Unaligned for [T; N]);
909c3739801SMiguel Ojeda     assert_unaligned!([(); 0], [(); 1], [u8; 0], [u8; 1]);
910c3739801SMiguel Ojeda     unsafe_impl!(T: Immutable => Immutable for [T]);
911c3739801SMiguel Ojeda     unsafe_impl!(T: TryFromBytes => TryFromBytes for [T]; |c| {
912c3739801SMiguel Ojeda         let c: Ptr<'_, [ReadOnly<T>], _> = c.cast::<_, crate::pointer::cast::CastUnsized, _>();
913c3739801SMiguel Ojeda 
914c3739801SMiguel Ojeda         // SAFETY: Per the reference [1]:
915c3739801SMiguel Ojeda         //
916c3739801SMiguel Ojeda         //   An array of `[T; N]` has a size of `size_of::<T>() * N` and the
917c3739801SMiguel Ojeda         //   same alignment of `T`. Arrays are laid out so that the zero-based
918c3739801SMiguel Ojeda         //   `nth` element of the array is offset from the start of the array by
919c3739801SMiguel Ojeda         //   `n * size_of::<T>()` bytes.
920c3739801SMiguel Ojeda         //
921c3739801SMiguel Ojeda         //   ...
922c3739801SMiguel Ojeda         //
923c3739801SMiguel Ojeda         //   Slices have the same layout as the section of the array they slice.
924c3739801SMiguel Ojeda         //
925c3739801SMiguel Ojeda         // In other words, the layout of a `[T] is a sequence of `T`s laid out
926c3739801SMiguel Ojeda         // back-to-back with no bytes in between. If all elements in `candidate`
927c3739801SMiguel Ojeda         // are `is_bit_valid`, so too is `candidate`.
928c3739801SMiguel Ojeda         //
929c3739801SMiguel Ojeda         // Note that any of the below calls may panic, but it would still be
930c3739801SMiguel Ojeda         // sound even if it did. `is_bit_valid` does not promise that it will
931c3739801SMiguel Ojeda         // not panic (in fact, it explicitly warns that it's a possibility), and
932c3739801SMiguel Ojeda         // we have not violated any safety invariants that we must fix before
933c3739801SMiguel Ojeda         // returning.
934c3739801SMiguel Ojeda         c.iter().all(<T as TryFromBytes>::is_bit_valid)
935c3739801SMiguel Ojeda     });
936c3739801SMiguel Ojeda     unsafe_impl!(T: FromZeros => FromZeros for [T]);
937c3739801SMiguel Ojeda     unsafe_impl!(T: FromBytes => FromBytes for [T]);
938c3739801SMiguel Ojeda     unsafe_impl!(T: IntoBytes => IntoBytes for [T]);
939c3739801SMiguel Ojeda     unsafe_impl!(T: Unaligned => Unaligned for [T]);
940c3739801SMiguel Ojeda };
941c3739801SMiguel Ojeda 
942c3739801SMiguel Ojeda // SAFETY:
943c3739801SMiguel Ojeda // - `Immutable`: Raw pointers do not contain any `UnsafeCell`s.
944c3739801SMiguel Ojeda // - `FromZeros`: For thin pointers (note that `T: Sized`), the zero pointer is
945c3739801SMiguel Ojeda //   considered "null". [1] No operations which require provenance are legal on
946c3739801SMiguel Ojeda //   null pointers, so this is not a footgun.
947c3739801SMiguel Ojeda // - `TryFromBytes`: By the same reasoning as for `FromZeroes`, we can implement
948c3739801SMiguel Ojeda //   `TryFromBytes` for thin pointers provided that
949c3739801SMiguel Ojeda //   [`TryFromByte::is_bit_valid`] only produces `true` for zeroed bytes.
950c3739801SMiguel Ojeda //
951c3739801SMiguel Ojeda // NOTE(#170): Implementing `FromBytes` and `IntoBytes` for raw pointers would
952c3739801SMiguel Ojeda // be sound, but carries provenance footguns. We want to support `FromBytes` and
953c3739801SMiguel Ojeda // `IntoBytes` for raw pointers eventually, but we are holding off until we can
954c3739801SMiguel Ojeda // figure out how to address those footguns.
955c3739801SMiguel Ojeda //
956c3739801SMiguel Ojeda // [1] Per https://doc.rust-lang.org/1.81.0/std/ptr/fn.null.html:
957c3739801SMiguel Ojeda //
958c3739801SMiguel Ojeda //   Creates a null raw pointer.
959c3739801SMiguel Ojeda //
960c3739801SMiguel Ojeda //   This function is equivalent to zero-initializing the pointer:
961c3739801SMiguel Ojeda //   `MaybeUninit::<*const T>::zeroed().assume_init()`.
962c3739801SMiguel Ojeda //
963c3739801SMiguel Ojeda //   The resulting pointer has the address 0.
964c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
965c3739801SMiguel Ojeda const _: () = unsafe {
966c3739801SMiguel Ojeda     unsafe_impl!(T: ?Sized => Immutable for *const T);
967c3739801SMiguel Ojeda     unsafe_impl!(T: ?Sized => Immutable for *mut T);
968c3739801SMiguel Ojeda     unsafe_impl!(T => TryFromBytes for *const T; |c| pointer::is_zeroed(c));
969c3739801SMiguel Ojeda     unsafe_impl!(T => FromZeros for *const T);
970c3739801SMiguel Ojeda     unsafe_impl!(T => TryFromBytes for *mut T; |c| pointer::is_zeroed(c));
971c3739801SMiguel Ojeda     unsafe_impl!(T => FromZeros for *mut T);
972c3739801SMiguel Ojeda };
973c3739801SMiguel Ojeda 
974c3739801SMiguel Ojeda // SAFETY: `NonNull<T>` self-evidently does not contain `UnsafeCell`s. This is
975c3739801SMiguel Ojeda // not a proof, but we are accepting this as a known risk per #1358.
976c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(T: ?Sized => Immutable for NonNull<T>) };
977c3739801SMiguel Ojeda 
978c3739801SMiguel Ojeda // SAFETY: Reference types do not contain any `UnsafeCell`s.
979c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)]
980c3739801SMiguel Ojeda const _: () = unsafe {
981c3739801SMiguel Ojeda     unsafe_impl!(T: ?Sized => Immutable for &'_ T);
982c3739801SMiguel Ojeda     unsafe_impl!(T: ?Sized => Immutable for &'_ mut T);
983c3739801SMiguel Ojeda };
984c3739801SMiguel Ojeda 
985c3739801SMiguel Ojeda // SAFETY: `Option` is not `#[non_exhaustive]` [1], which means that the types
986c3739801SMiguel Ojeda // in its variants cannot change, and no new variants can be added. `Option<T>`
987c3739801SMiguel Ojeda // does not contain any `UnsafeCell`s outside of `T`. [1]
988c3739801SMiguel Ojeda //
989c3739801SMiguel Ojeda // [1] https://doc.rust-lang.org/core/option/enum.Option.html
990c3739801SMiguel Ojeda const _: () = unsafe { unsafe_impl!(T: Immutable => Immutable for Option<T>) };
991c3739801SMiguel Ojeda 
992c3739801SMiguel Ojeda mod tuples {
993c3739801SMiguel Ojeda     use super::*;
994c3739801SMiguel Ojeda 
995c3739801SMiguel Ojeda     /// Generates various trait implementations for tuples.
996c3739801SMiguel Ojeda     ///
997c3739801SMiguel Ojeda     /// # Safety
998c3739801SMiguel Ojeda     ///
999c3739801SMiguel Ojeda     /// `impl_tuple!` should be provided name-number pairs, where each number is
1000c3739801SMiguel Ojeda     /// the ordinal of the preceding type name.
1001c3739801SMiguel Ojeda     macro_rules! impl_tuple {
1002c3739801SMiguel Ojeda         // Entry point.
1003c3739801SMiguel Ojeda         ($($T:ident $I:tt),+ $(,)?) => {
1004c3739801SMiguel Ojeda             crate::util::macros::__unsafe();
1005c3739801SMiguel Ojeda             impl_tuple!(@all [] [$($T $I)+]);
1006c3739801SMiguel Ojeda         };
1007c3739801SMiguel Ojeda 
1008c3739801SMiguel Ojeda         // Build up the set of tuple types (i.e., `(A,)`, `(A, B)`, `(A, B, C)`,
1009c3739801SMiguel Ojeda         // etc.) Trait implementations that do not depend on field index may be
1010c3739801SMiguel Ojeda         // added to this branch.
1011c3739801SMiguel Ojeda         (@all [$($head_T:ident $head_I:tt)*] [$next_T:ident $next_I:tt $($tail:tt)*]) => {
1012c3739801SMiguel Ojeda             // SAFETY: If all fields of the tuple `Self` are `Immutable`, so too is `Self`.
1013c3739801SMiguel Ojeda             unsafe_impl!($($head_T: Immutable,)* $next_T: Immutable => Immutable for ($($head_T,)* $next_T,));
1014c3739801SMiguel Ojeda 
1015c3739801SMiguel Ojeda             // SAFETY: If all fields in `c` are `is_bit_valid`, so too is `c`.
1016c3739801SMiguel Ojeda             unsafe_impl!($($head_T: TryFromBytes,)* $next_T: TryFromBytes => TryFromBytes for ($($head_T,)* $next_T,); |c| {
1017c3739801SMiguel Ojeda                 let mut c = c;
1018c3739801SMiguel Ojeda                 $(TryFromBytes::is_bit_valid(into_inner!(c.reborrow().project::<_, { crate::STRUCT_VARIANT_ID }, { crate::ident_id!($head_I) }>())) &&)*
1019c3739801SMiguel Ojeda                     TryFromBytes::is_bit_valid(into_inner!(c.reborrow().project::<_, { crate::STRUCT_VARIANT_ID }, { crate::ident_id!($next_I) }>()))
1020c3739801SMiguel Ojeda             });
1021c3739801SMiguel Ojeda 
1022c3739801SMiguel Ojeda             // SAFETY: If all fields in `Self` are `FromZeros`, so too is `Self`.
1023c3739801SMiguel Ojeda             unsafe_impl!($($head_T: FromZeros,)* $next_T: FromZeros => FromZeros for ($($head_T,)* $next_T,));
1024c3739801SMiguel Ojeda 
1025c3739801SMiguel Ojeda             // SAFETY: If all fields in `Self` are `FromBytes`, so too is `Self`.
1026c3739801SMiguel Ojeda             unsafe_impl!($($head_T: FromBytes,)* $next_T: FromBytes => FromBytes for ($($head_T,)* $next_T,));
1027c3739801SMiguel Ojeda 
1028c3739801SMiguel Ojeda             // SAFETY: See safety comment on `ProjectToTag`.
1029c3739801SMiguel Ojeda             unsafe impl<$($head_T,)* $next_T> crate::HasTag for ($($head_T,)* $next_T,) {
1030c3739801SMiguel Ojeda                 #[inline]
1031c3739801SMiguel Ojeda                 fn only_derive_is_allowed_to_implement_this_trait()
1032c3739801SMiguel Ojeda                 where
1033c3739801SMiguel Ojeda                     Self: Sized
1034c3739801SMiguel Ojeda                 {}
1035c3739801SMiguel Ojeda 
1036c3739801SMiguel Ojeda                 type Tag = ();
1037c3739801SMiguel Ojeda 
1038c3739801SMiguel Ojeda                 // SAFETY: It is trivially sound to project any pointer to a
1039c3739801SMiguel Ojeda                 // pointer to a type of size zero and alignment 1 (which `()` is
1040c3739801SMiguel Ojeda                 // [1]). Such a pointer will trivially satisfy its aliasing and
1041c3739801SMiguel Ojeda                 // validity requirements (since it has a zero-sized referent),
1042c3739801SMiguel Ojeda                 // and its alignment requirement (since it is aligned to 1).
1043c3739801SMiguel Ojeda                 //
1044c3739801SMiguel Ojeda                 // [1] Per https://doc.rust-lang.org/1.92.0/reference/type-layout.html#r-layout.tuple.unit:
1045c3739801SMiguel Ojeda                 //
1046c3739801SMiguel Ojeda                 //     [T]he unit tuple (`()`)... is guaranteed as a zero-sized
1047c3739801SMiguel Ojeda                 //     type to have a size of 0 and an alignment of 1.
1048c3739801SMiguel Ojeda                 type ProjectToTag = crate::pointer::cast::CastToUnit;
1049c3739801SMiguel Ojeda             }
1050c3739801SMiguel Ojeda 
1051c3739801SMiguel Ojeda             // Generate impls that depend on tuple index.
1052c3739801SMiguel Ojeda             impl_tuple!(@variants
1053c3739801SMiguel Ojeda                 [$($head_T $head_I)* $next_T $next_I]
1054c3739801SMiguel Ojeda                 []
1055c3739801SMiguel Ojeda                 [$($head_T $head_I)* $next_T $next_I]
1056c3739801SMiguel Ojeda             );
1057c3739801SMiguel Ojeda 
1058c3739801SMiguel Ojeda             // Recurse to next tuple size
1059c3739801SMiguel Ojeda             impl_tuple!(@all [$($head_T $head_I)* $next_T $next_I] [$($tail)*]);
1060c3739801SMiguel Ojeda         };
1061c3739801SMiguel Ojeda         (@all [$($head_T:ident $head_I:tt)*] []) => {};
1062c3739801SMiguel Ojeda 
1063c3739801SMiguel Ojeda         // Emit trait implementations that depend on field index.
1064c3739801SMiguel Ojeda         (@variants
1065c3739801SMiguel Ojeda             // The full tuple definition in type–index pairs.
1066c3739801SMiguel Ojeda             [$($AllT:ident $AllI:tt)+]
1067c3739801SMiguel Ojeda             // Types before the current index.
1068c3739801SMiguel Ojeda             [$($BeforeT:ident)*]
1069c3739801SMiguel Ojeda             // The types and indices at and after the current index.
1070c3739801SMiguel Ojeda             [$CurrT:ident $CurrI:tt $($AfterT:ident $AfterI:tt)*]
1071c3739801SMiguel Ojeda         ) => {
1072c3739801SMiguel Ojeda             // SAFETY:
1073c3739801SMiguel Ojeda             // - `Self` is a struct (albeit anonymous), so `VARIANT_ID` is
1074c3739801SMiguel Ojeda             //   `STRUCT_VARIANT_ID`.
1075c3739801SMiguel Ojeda             // - `$CurrI` is the field at index `$CurrI`, so `FIELD_ID` is
1076c3739801SMiguel Ojeda             //   `zerocopy::ident_id!($CurrI)`
1077c3739801SMiguel Ojeda             // - `()` has the same visibility as the `.$CurrI` field (ie, `.0`,
1078c3739801SMiguel Ojeda             //   `.1`, etc)
1079c3739801SMiguel Ojeda             // - `Type` has the same type as `$CurrI`; i.e., `$CurrT`.
1080c3739801SMiguel Ojeda             unsafe impl<$($AllT),+> crate::HasField<
1081c3739801SMiguel Ojeda                 (),
1082c3739801SMiguel Ojeda                 { crate::STRUCT_VARIANT_ID },
1083c3739801SMiguel Ojeda                 { crate::ident_id!($CurrI)}
1084c3739801SMiguel Ojeda             > for ($($AllT,)+) {
1085c3739801SMiguel Ojeda                 #[inline]
1086c3739801SMiguel Ojeda                 fn only_derive_is_allowed_to_implement_this_trait()
1087c3739801SMiguel Ojeda                 where
1088c3739801SMiguel Ojeda                     Self: Sized
1089c3739801SMiguel Ojeda                 {}
1090c3739801SMiguel Ojeda 
1091c3739801SMiguel Ojeda                 type Type = $CurrT;
1092c3739801SMiguel Ojeda 
1093c3739801SMiguel Ojeda                 #[inline(always)]
1094c3739801SMiguel Ojeda                 fn project(slf: crate::PtrInner<'_, Self>) -> *mut Self::Type {
1095c3739801SMiguel Ojeda                     let slf = slf.as_non_null().as_ptr();
1096c3739801SMiguel Ojeda                     // SAFETY: `PtrInner` promises it references either a zero-sized
1097c3739801SMiguel Ojeda                     // byte range, or else will reference a byte range that is
1098c3739801SMiguel Ojeda                     // entirely contained within an allocated object. In either
1099c3739801SMiguel Ojeda                     // case, this guarantees that `(*slf).$CurrI` is in-bounds of
1100c3739801SMiguel Ojeda                     // `slf`.
1101c3739801SMiguel Ojeda                     unsafe { core::ptr::addr_of_mut!((*slf).$CurrI) }
1102c3739801SMiguel Ojeda                 }
1103c3739801SMiguel Ojeda             }
1104c3739801SMiguel Ojeda 
1105c3739801SMiguel Ojeda             // SAFETY: See comments on items.
1106c3739801SMiguel Ojeda             unsafe impl<Aliasing, Alignment, $($AllT),+> crate::ProjectField<
1107c3739801SMiguel Ojeda                 (),
1108c3739801SMiguel Ojeda                 (Aliasing, Alignment, crate::invariant::Uninit),
1109c3739801SMiguel Ojeda                 { crate::STRUCT_VARIANT_ID },
1110c3739801SMiguel Ojeda                 { crate::ident_id!($CurrI)}
1111c3739801SMiguel Ojeda             > for ($($AllT,)+)
1112c3739801SMiguel Ojeda             where
1113c3739801SMiguel Ojeda                 Aliasing: crate::invariant::Aliasing,
1114c3739801SMiguel Ojeda                 Alignment: crate::invariant::Alignment,
1115c3739801SMiguel Ojeda             {
1116c3739801SMiguel Ojeda                 #[inline]
1117c3739801SMiguel Ojeda                 fn only_derive_is_allowed_to_implement_this_trait()
1118c3739801SMiguel Ojeda                 where
1119c3739801SMiguel Ojeda                     Self: Sized
1120c3739801SMiguel Ojeda                 {}
1121c3739801SMiguel Ojeda 
1122c3739801SMiguel Ojeda                 // SAFETY: Tuples are product types whose fields are
1123c3739801SMiguel Ojeda                 // well-aligned, so projection preserves both the alignment and
1124c3739801SMiguel Ojeda                 // validity invariants of the outer pointer.
1125c3739801SMiguel Ojeda                 type Invariants = (Aliasing, Alignment, crate::invariant::Uninit);
1126c3739801SMiguel Ojeda 
1127c3739801SMiguel Ojeda                 // SAFETY: Tuples are product types and so projection is infallible;
1128c3739801SMiguel Ojeda                 type Error = core::convert::Infallible;
1129c3739801SMiguel Ojeda             }
1130c3739801SMiguel Ojeda 
1131c3739801SMiguel Ojeda             // SAFETY: See comments on items.
1132c3739801SMiguel Ojeda             unsafe impl<Aliasing, Alignment, $($AllT),+> crate::ProjectField<
1133c3739801SMiguel Ojeda                 (),
1134c3739801SMiguel Ojeda                 (Aliasing, Alignment, crate::invariant::Initialized),
1135c3739801SMiguel Ojeda                 { crate::STRUCT_VARIANT_ID },
1136c3739801SMiguel Ojeda                 { crate::ident_id!($CurrI)}
1137c3739801SMiguel Ojeda             > for ($($AllT,)+)
1138c3739801SMiguel Ojeda             where
1139c3739801SMiguel Ojeda                 Aliasing: crate::invariant::Aliasing,
1140c3739801SMiguel Ojeda                 Alignment: crate::invariant::Alignment,
1141c3739801SMiguel Ojeda             {
1142c3739801SMiguel Ojeda                 #[inline]
1143c3739801SMiguel Ojeda                 fn only_derive_is_allowed_to_implement_this_trait()
1144c3739801SMiguel Ojeda                 where
1145c3739801SMiguel Ojeda                     Self: Sized
1146c3739801SMiguel Ojeda                 {}
1147c3739801SMiguel Ojeda 
1148c3739801SMiguel Ojeda                 // SAFETY: Tuples are product types whose fields are
1149c3739801SMiguel Ojeda                 // well-aligned, so projection preserves both the alignment and
1150c3739801SMiguel Ojeda                 // validity invariants of the outer pointer.
1151c3739801SMiguel Ojeda                 type Invariants = (Aliasing, Alignment, crate::invariant::Initialized);
1152c3739801SMiguel Ojeda 
1153c3739801SMiguel Ojeda                 // SAFETY: Tuples are product types and so projection is infallible;
1154c3739801SMiguel Ojeda                 type Error = core::convert::Infallible;
1155c3739801SMiguel Ojeda             }
1156c3739801SMiguel Ojeda 
1157c3739801SMiguel Ojeda             // SAFETY: See comments on items.
1158c3739801SMiguel Ojeda             unsafe impl<Aliasing, Alignment, $($AllT),+> crate::ProjectField<
1159c3739801SMiguel Ojeda                 (),
1160c3739801SMiguel Ojeda                 (Aliasing, Alignment, crate::invariant::Valid),
1161c3739801SMiguel Ojeda                 { crate::STRUCT_VARIANT_ID },
1162c3739801SMiguel Ojeda                 { crate::ident_id!($CurrI)}
1163c3739801SMiguel Ojeda             > for ($($AllT,)+)
1164c3739801SMiguel Ojeda             where
1165c3739801SMiguel Ojeda                 Aliasing: crate::invariant::Aliasing,
1166c3739801SMiguel Ojeda                 Alignment: crate::invariant::Alignment,
1167c3739801SMiguel Ojeda             {
1168c3739801SMiguel Ojeda                 #[inline]
1169c3739801SMiguel Ojeda                 fn only_derive_is_allowed_to_implement_this_trait()
1170c3739801SMiguel Ojeda                 where
1171c3739801SMiguel Ojeda                     Self: Sized
1172c3739801SMiguel Ojeda                 {}
1173c3739801SMiguel Ojeda 
1174c3739801SMiguel Ojeda                 // SAFETY: Tuples are product types whose fields are
1175c3739801SMiguel Ojeda                 // well-aligned, so projection preserves both the alignment and
1176c3739801SMiguel Ojeda                 // validity invariants of the outer pointer.
1177c3739801SMiguel Ojeda                 type Invariants = (Aliasing, Alignment, crate::invariant::Valid);
1178c3739801SMiguel Ojeda 
1179c3739801SMiguel Ojeda                 // SAFETY: Tuples are product types and so projection is infallible;
1180c3739801SMiguel Ojeda                 type Error = core::convert::Infallible;
1181c3739801SMiguel Ojeda             }
1182c3739801SMiguel Ojeda 
1183c3739801SMiguel Ojeda             // Recurse to the next index.
1184c3739801SMiguel Ojeda             impl_tuple!(@variants [$($AllT $AllI)+] [$($BeforeT)* $CurrT] [$($AfterT $AfterI)*]);
1185c3739801SMiguel Ojeda         };
1186c3739801SMiguel Ojeda         (@variants [$($AllT:ident $AllI:tt)+] [$($BeforeT:ident)*] []) => {};
1187c3739801SMiguel Ojeda     }
1188c3739801SMiguel Ojeda 
1189c3739801SMiguel Ojeda     // SAFETY: `impl_tuple` is provided name-number pairs, where number is the
1190c3739801SMiguel Ojeda     // ordinal of the name.
1191c3739801SMiguel Ojeda     #[allow(clippy::multiple_unsafe_ops_per_block)]
1192c3739801SMiguel Ojeda     const _: () = unsafe {
1193c3739801SMiguel Ojeda         impl_tuple! {
1194c3739801SMiguel Ojeda             A 0,
1195c3739801SMiguel Ojeda             B 1,
1196c3739801SMiguel Ojeda             C 2,
1197c3739801SMiguel Ojeda             D 3,
1198c3739801SMiguel Ojeda             E 4,
1199c3739801SMiguel Ojeda             F 5,
1200c3739801SMiguel Ojeda             G 6,
1201c3739801SMiguel Ojeda             H 7,
1202c3739801SMiguel Ojeda             I 8,
1203c3739801SMiguel Ojeda             J 9,
1204c3739801SMiguel Ojeda             K 10,
1205c3739801SMiguel Ojeda             L 11,
1206c3739801SMiguel Ojeda             M 12,
1207c3739801SMiguel Ojeda             N 13,
1208c3739801SMiguel Ojeda             O 14,
1209c3739801SMiguel Ojeda             P 15,
1210c3739801SMiguel Ojeda             Q 16,
1211c3739801SMiguel Ojeda             R 17,
1212c3739801SMiguel Ojeda             S 18,
1213c3739801SMiguel Ojeda             T 19,
1214c3739801SMiguel Ojeda             U 20,
1215c3739801SMiguel Ojeda             V 21,
1216c3739801SMiguel Ojeda             W 22,
1217c3739801SMiguel Ojeda             X 23,
1218c3739801SMiguel Ojeda             Y 24,
1219c3739801SMiguel Ojeda             Z 25,
1220c3739801SMiguel Ojeda         };
1221c3739801SMiguel Ojeda     };
1222c3739801SMiguel Ojeda }
1223c3739801SMiguel Ojeda 
1224c3739801SMiguel Ojeda // SIMD support
1225c3739801SMiguel Ojeda //
1226c3739801SMiguel Ojeda // Per the Unsafe Code Guidelines Reference [1]:
1227c3739801SMiguel Ojeda //
1228c3739801SMiguel Ojeda //   Packed SIMD vector types are `repr(simd)` homogeneous tuple-structs
1229c3739801SMiguel Ojeda //   containing `N` elements of type `T` where `N` is a power-of-two and the
1230c3739801SMiguel Ojeda //   size and alignment requirements of `T` are equal:
1231c3739801SMiguel Ojeda //
1232c3739801SMiguel Ojeda //   ```rust
1233c3739801SMiguel Ojeda //   #[repr(simd)]
1234c3739801SMiguel Ojeda //   struct Vector<T, N>(T_0, ..., T_(N - 1));
1235c3739801SMiguel Ojeda //   ```
1236c3739801SMiguel Ojeda //
1237c3739801SMiguel Ojeda //   ...
1238c3739801SMiguel Ojeda //
1239c3739801SMiguel Ojeda //   The size of `Vector` is `N * size_of::<T>()` and its alignment is an
1240c3739801SMiguel Ojeda //   implementation-defined function of `T` and `N` greater than or equal to
1241c3739801SMiguel Ojeda //   `align_of::<T>()`.
1242c3739801SMiguel Ojeda //
1243c3739801SMiguel Ojeda //   ...
1244c3739801SMiguel Ojeda //
1245c3739801SMiguel Ojeda //   Vector elements are laid out in source field order, enabling random access
1246c3739801SMiguel Ojeda //   to vector elements by reinterpreting the vector as an array:
1247c3739801SMiguel Ojeda //
1248c3739801SMiguel Ojeda //   ```rust
1249c3739801SMiguel Ojeda //   union U {
1250c3739801SMiguel Ojeda //      vec: Vector<T, N>,
1251c3739801SMiguel Ojeda //      arr: [T; N]
1252c3739801SMiguel Ojeda //   }
1253c3739801SMiguel Ojeda //
1254c3739801SMiguel Ojeda //   assert_eq!(size_of::<Vector<T, N>>(), size_of::<[T; N]>());
1255c3739801SMiguel Ojeda //   assert!(align_of::<Vector<T, N>>() >= align_of::<[T; N]>());
1256c3739801SMiguel Ojeda //
1257c3739801SMiguel Ojeda //   unsafe {
1258c3739801SMiguel Ojeda //     let u = U { vec: Vector<T, N>(t_0, ..., t_(N - 1)) };
1259c3739801SMiguel Ojeda //
1260c3739801SMiguel Ojeda //     assert_eq!(u.vec.0, u.arr[0]);
1261c3739801SMiguel Ojeda //     // ...
1262c3739801SMiguel Ojeda //     assert_eq!(u.vec.(N - 1), u.arr[N - 1]);
1263c3739801SMiguel Ojeda //   }
1264c3739801SMiguel Ojeda //   ```
1265c3739801SMiguel Ojeda //
1266c3739801SMiguel Ojeda // Given this background, we can observe that:
1267c3739801SMiguel Ojeda // - The size and bit pattern requirements of a SIMD type are equivalent to the
1268c3739801SMiguel Ojeda //   equivalent array type. Thus, for any SIMD type whose primitive `T` is
1269c3739801SMiguel Ojeda //   `Immutable`, `TryFromBytes`, `FromZeros`, `FromBytes`, or `IntoBytes`, that
1270c3739801SMiguel Ojeda //   SIMD type is also `Immutable`, `TryFromBytes`, `FromZeros`, `FromBytes`, or
1271c3739801SMiguel Ojeda //   `IntoBytes` respectively.
1272c3739801SMiguel Ojeda // - Since no upper bound is placed on the alignment, no SIMD type can be
1273c3739801SMiguel Ojeda //   guaranteed to be `Unaligned`.
1274c3739801SMiguel Ojeda //
1275c3739801SMiguel Ojeda // Also per [1]:
1276c3739801SMiguel Ojeda //
1277c3739801SMiguel Ojeda //   This chapter represents the consensus from issue #38. The statements in
1278c3739801SMiguel Ojeda //   here are not (yet) "guaranteed" not to change until an RFC ratifies them.
1279c3739801SMiguel Ojeda //
1280c3739801SMiguel Ojeda // See issue #38 [2]. While this behavior is not technically guaranteed, the
1281c3739801SMiguel Ojeda // likelihood that the behavior will change such that SIMD types are no longer
1282c3739801SMiguel Ojeda // `TryFromBytes`, `FromZeros`, `FromBytes`, or `IntoBytes` is next to zero, as
1283c3739801SMiguel Ojeda // that would defeat the entire purpose of SIMD types. Nonetheless, we put this
1284c3739801SMiguel Ojeda // behavior behind the `simd` Cargo feature, which requires consumers to opt
1285c3739801SMiguel Ojeda // into this stability hazard.
1286c3739801SMiguel Ojeda //
1287c3739801SMiguel Ojeda // [1] https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html
1288c3739801SMiguel Ojeda // [2] https://github.com/rust-lang/unsafe-code-guidelines/issues/38
1289c3739801SMiguel Ojeda #[cfg(feature = "simd")]
1290c3739801SMiguel Ojeda #[cfg_attr(doc_cfg, doc(cfg(feature = "simd")))]
1291c3739801SMiguel Ojeda mod simd {
1292c3739801SMiguel Ojeda     /// Defines a module which implements `TryFromBytes`, `FromZeros`,
1293c3739801SMiguel Ojeda     /// `FromBytes`, and `IntoBytes` for a set of types from a module in
1294c3739801SMiguel Ojeda     /// `core::arch`.
1295c3739801SMiguel Ojeda     ///
1296c3739801SMiguel Ojeda     /// `$arch` is both the name of the defined module and the name of the
1297c3739801SMiguel Ojeda     /// module in `core::arch`, and `$typ` is the list of items from that module
1298c3739801SMiguel Ojeda     /// to implement `FromZeros`, `FromBytes`, and `IntoBytes` for.
1299c3739801SMiguel Ojeda     #[allow(unused_macros)] // `allow(unused_macros)` is needed because some
1300c3739801SMiguel Ojeda                             // target/feature combinations don't emit any impls
1301c3739801SMiguel Ojeda                             // and thus don't use this macro.
1302c3739801SMiguel Ojeda     macro_rules! simd_arch_mod {
1303c3739801SMiguel Ojeda         ($(#[cfg $cfg:tt])* $(#[cfg_attr $cfg_attr:tt])? $arch:ident, $mod:ident, $($typ:ident),*) => {
1304c3739801SMiguel Ojeda             $(#[cfg $cfg])*
1305c3739801SMiguel Ojeda             #[cfg_attr(doc_cfg, doc(cfg $($cfg)*))]
1306c3739801SMiguel Ojeda             $(#[cfg_attr $cfg_attr])?
1307c3739801SMiguel Ojeda             mod $mod {
1308c3739801SMiguel Ojeda                 use core::arch::$arch::{$($typ),*};
1309c3739801SMiguel Ojeda 
1310c3739801SMiguel Ojeda                 use crate::*;
1311c3739801SMiguel Ojeda                 impl_known_layout!($($typ),*);
1312c3739801SMiguel Ojeda                 // SAFETY: See comment on module definition for justification.
1313c3739801SMiguel Ojeda                 #[allow(clippy::multiple_unsafe_ops_per_block)]
1314c3739801SMiguel Ojeda                 const _: () = unsafe {
1315c3739801SMiguel Ojeda                     $( unsafe_impl!($typ: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); )*
1316c3739801SMiguel Ojeda                 };
1317c3739801SMiguel Ojeda             }
1318c3739801SMiguel Ojeda         };
1319c3739801SMiguel Ojeda     }
1320c3739801SMiguel Ojeda 
1321c3739801SMiguel Ojeda     #[rustfmt::skip]
1322c3739801SMiguel Ojeda     const _: () = {
1323c3739801SMiguel Ojeda         simd_arch_mod!(
1324c3739801SMiguel Ojeda             #[cfg(target_arch = "x86")]
1325c3739801SMiguel Ojeda             x86, x86, __m128, __m128d, __m128i, __m256, __m256d, __m256i
1326c3739801SMiguel Ojeda         );
1327c3739801SMiguel Ojeda         #[cfg(not(no_zerocopy_simd_x86_avx12_1_89_0))]
1328c3739801SMiguel Ojeda         simd_arch_mod!(
1329c3739801SMiguel Ojeda             #[cfg(target_arch = "x86")]
1330c3739801SMiguel Ojeda             #[cfg_attr(doc_cfg, doc(cfg(rust = "1.89.0")))]
1331c3739801SMiguel Ojeda             x86, x86_nightly, __m512bh, __m512, __m512d, __m512i
1332c3739801SMiguel Ojeda         );
1333c3739801SMiguel Ojeda         simd_arch_mod!(
1334c3739801SMiguel Ojeda             #[cfg(target_arch = "x86_64")]
1335c3739801SMiguel Ojeda             x86_64, x86_64, __m128, __m128d, __m128i, __m256, __m256d, __m256i
1336c3739801SMiguel Ojeda         );
1337c3739801SMiguel Ojeda         #[cfg(not(no_zerocopy_simd_x86_avx12_1_89_0))]
1338c3739801SMiguel Ojeda         simd_arch_mod!(
1339c3739801SMiguel Ojeda             #[cfg(target_arch = "x86_64")]
1340c3739801SMiguel Ojeda             #[cfg_attr(doc_cfg, doc(cfg(rust = "1.89.0")))]
1341c3739801SMiguel Ojeda             x86_64, x86_64_nightly, __m512bh, __m512, __m512d, __m512i
1342c3739801SMiguel Ojeda         );
1343c3739801SMiguel Ojeda         simd_arch_mod!(
1344c3739801SMiguel Ojeda             #[cfg(target_arch = "wasm32")]
1345c3739801SMiguel Ojeda             wasm32, wasm32, v128
1346c3739801SMiguel Ojeda         );
1347c3739801SMiguel Ojeda         simd_arch_mod!(
1348c3739801SMiguel Ojeda             #[cfg(all(feature = "simd-nightly", target_arch = "powerpc"))]
1349c3739801SMiguel Ojeda             powerpc, powerpc, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long
1350c3739801SMiguel Ojeda         );
1351c3739801SMiguel Ojeda         simd_arch_mod!(
1352c3739801SMiguel Ojeda             #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))]
1353c3739801SMiguel Ojeda             powerpc64, powerpc64, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long
1354c3739801SMiguel Ojeda         );
1355c3739801SMiguel Ojeda         // NOTE: NEON intrinsics were broken on big-endian platforms from their stabilization up to
1356c3739801SMiguel Ojeda         // Rust 1.87. (Context in https://github.com/rust-lang/stdarch/issues/1484). Support is
1357c3739801SMiguel Ojeda         // split in two different version ranges on top of the base configuration, requiring either
1358c3739801SMiguel Ojeda         // little endian or the more recent version to be detected as well.
1359c3739801SMiguel Ojeda         #[cfg(not(no_zerocopy_aarch64_simd_1_59_0))]
1360c3739801SMiguel Ojeda         simd_arch_mod!(
1361c3739801SMiguel Ojeda             #[cfg(all(
1362c3739801SMiguel Ojeda                 target_arch = "aarch64",
1363c3739801SMiguel Ojeda                 any(
1364c3739801SMiguel Ojeda                     target_endian = "little",
1365c3739801SMiguel Ojeda                     not(no_zerocopy_aarch64_simd_be_1_87_0)
1366c3739801SMiguel Ojeda                 )
1367c3739801SMiguel Ojeda             ))]
1368c3739801SMiguel Ojeda             #[cfg_attr(
1369c3739801SMiguel Ojeda                 doc_cfg,
1370c3739801SMiguel Ojeda                 doc(cfg(all(target_arch = "aarch64", any(
1371c3739801SMiguel Ojeda                     all(rust = "1.59.0", target_endian = "little"),
1372c3739801SMiguel Ojeda                     rust = "1.87.0",
1373c3739801SMiguel Ojeda                 ))))
1374c3739801SMiguel Ojeda             )]
1375c3739801SMiguel Ojeda             aarch64, aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t,
1376c3739801SMiguel Ojeda             int8x8x3_t, int8x8x4_t, int8x16_t, int8x16x2_t, int8x16x3_t, int8x16x4_t, int16x4_t,
1377c3739801SMiguel Ojeda             int16x8_t, int32x2_t, int32x4_t, int64x1_t, int64x2_t, poly8x8_t, poly8x8x2_t, poly8x8x3_t,
1378c3739801SMiguel Ojeda             poly8x8x4_t, poly8x16_t, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t, poly16x4_t, poly16x8_t,
1379c3739801SMiguel Ojeda             poly64x1_t, poly64x2_t, uint8x8_t, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t, uint8x16_t,
1380c3739801SMiguel Ojeda             uint8x16x2_t, uint8x16x3_t, uint8x16x4_t, uint16x4_t, uint16x4x2_t, uint16x4x3_t,
1381c3739801SMiguel Ojeda             uint16x4x4_t, uint16x8_t, uint32x2_t, uint32x4_t, uint64x1_t, uint64x2_t
1382c3739801SMiguel Ojeda         );
1383c3739801SMiguel Ojeda     };
1384c3739801SMiguel Ojeda }
1385c3739801SMiguel Ojeda 
1386c3739801SMiguel Ojeda #[cfg(test)]
1387c3739801SMiguel Ojeda mod tests {
1388c3739801SMiguel Ojeda     use super::*;
1389c3739801SMiguel Ojeda 
1390c3739801SMiguel Ojeda     #[test]
1391c3739801SMiguel Ojeda     fn test_impls() {
1392c3739801SMiguel Ojeda         // A type that can supply test cases for testing
1393c3739801SMiguel Ojeda         // `TryFromBytes::is_bit_valid`. All types passed to `assert_impls!`
1394c3739801SMiguel Ojeda         // must implement this trait; that macro uses it to generate runtime
1395c3739801SMiguel Ojeda         // tests for `TryFromBytes` impls.
1396c3739801SMiguel Ojeda         //
1397c3739801SMiguel Ojeda         // All `T: FromBytes` types are provided with a blanket impl. Other
1398c3739801SMiguel Ojeda         // types must implement `TryFromBytesTestable` directly (ie using
1399c3739801SMiguel Ojeda         // `impl_try_from_bytes_testable!`).
1400c3739801SMiguel Ojeda         trait TryFromBytesTestable {
1401c3739801SMiguel Ojeda             fn with_passing_test_cases<F: Fn(Box<ReadOnly<Self>>)>(f: F);
1402c3739801SMiguel Ojeda             fn with_failing_test_cases<F: Fn(&mut [u8])>(f: F);
1403c3739801SMiguel Ojeda         }
1404c3739801SMiguel Ojeda 
1405c3739801SMiguel Ojeda         impl<T: FromBytes> TryFromBytesTestable for T {
1406c3739801SMiguel Ojeda             fn with_passing_test_cases<F: Fn(Box<ReadOnly<Self>>)>(f: F) {
1407c3739801SMiguel Ojeda                 // Test with a zeroed value.
1408c3739801SMiguel Ojeda                 f(ReadOnly::<Self>::new_box_zeroed().unwrap());
1409c3739801SMiguel Ojeda 
1410c3739801SMiguel Ojeda                 let ffs = {
1411c3739801SMiguel Ojeda                     let mut t = ReadOnly::new(Self::new_zeroed());
1412c3739801SMiguel Ojeda                     let ptr: *mut T = ReadOnly::as_mut(&mut t);
1413c3739801SMiguel Ojeda                     // SAFETY: `T: FromBytes`
1414c3739801SMiguel Ojeda                     unsafe { ptr::write_bytes(ptr.cast::<u8>(), 0xFF, mem::size_of::<T>()) };
1415c3739801SMiguel Ojeda                     t
1416c3739801SMiguel Ojeda                 };
1417c3739801SMiguel Ojeda 
1418c3739801SMiguel Ojeda                 // Test with a value initialized with 0xFF.
1419c3739801SMiguel Ojeda                 f(Box::new(ffs));
1420c3739801SMiguel Ojeda             }
1421c3739801SMiguel Ojeda 
1422c3739801SMiguel Ojeda             fn with_failing_test_cases<F: Fn(&mut [u8])>(_f: F) {}
1423c3739801SMiguel Ojeda         }
1424c3739801SMiguel Ojeda 
1425c3739801SMiguel Ojeda         macro_rules! impl_try_from_bytes_testable_for_null_pointer_optimization {
1426c3739801SMiguel Ojeda             ($($tys:ty),*) => {
1427c3739801SMiguel Ojeda                 $(
1428c3739801SMiguel Ojeda                     impl TryFromBytesTestable for Option<$tys> {
1429c3739801SMiguel Ojeda                         fn with_passing_test_cases<F: Fn(Box<ReadOnly<Self>>)>(f: F) {
1430c3739801SMiguel Ojeda                             // Test with a zeroed value.
1431c3739801SMiguel Ojeda                             f(Box::new(ReadOnly::new(None)));
1432c3739801SMiguel Ojeda                         }
1433c3739801SMiguel Ojeda 
1434c3739801SMiguel Ojeda                         fn with_failing_test_cases<F: Fn(&mut [u8])>(f: F) {
1435c3739801SMiguel Ojeda                             for pos in 0..mem::size_of::<Self>() {
1436c3739801SMiguel Ojeda                                 let mut bytes = [0u8; mem::size_of::<Self>()];
1437c3739801SMiguel Ojeda                                 bytes[pos] = 0x01;
1438c3739801SMiguel Ojeda                                 f(&mut bytes[..]);
1439c3739801SMiguel Ojeda                             }
1440c3739801SMiguel Ojeda                         }
1441c3739801SMiguel Ojeda                     }
1442c3739801SMiguel Ojeda                 )*
1443c3739801SMiguel Ojeda             };
1444c3739801SMiguel Ojeda         }
1445c3739801SMiguel Ojeda 
1446c3739801SMiguel Ojeda         // Implements `TryFromBytesTestable`.
1447c3739801SMiguel Ojeda         macro_rules! impl_try_from_bytes_testable {
1448c3739801SMiguel Ojeda             // Base case for recursion (when the list of types has run out).
1449c3739801SMiguel Ojeda             (=> @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => {};
1450c3739801SMiguel Ojeda             // Implements for type(s) with no type parameters.
1451c3739801SMiguel Ojeda             ($ty:ty $(,$tys:ty)* => @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => {
1452c3739801SMiguel Ojeda                 impl TryFromBytesTestable for $ty {
1453c3739801SMiguel Ojeda                     impl_try_from_bytes_testable!(
1454c3739801SMiguel Ojeda                         @methods     @success $($success_case),*
1455c3739801SMiguel Ojeda                                  $(, @failure $($failure_case),*)?
1456c3739801SMiguel Ojeda                     );
1457c3739801SMiguel Ojeda                 }
1458c3739801SMiguel Ojeda                 impl_try_from_bytes_testable!($($tys),* => @success $($success_case),* $(, @failure $($failure_case),*)?);
1459c3739801SMiguel Ojeda             };
1460c3739801SMiguel Ojeda             // Implements for multiple types with no type parameters.
1461c3739801SMiguel Ojeda             ($($($ty:ty),* => @success $($success_case:expr), * $(, @failure $($failure_case:expr),*)?;)*) => {
1462c3739801SMiguel Ojeda                 $(
1463c3739801SMiguel Ojeda                     impl_try_from_bytes_testable!($($ty),* => @success $($success_case),* $(, @failure $($failure_case),*)*);
1464c3739801SMiguel Ojeda                 )*
1465c3739801SMiguel Ojeda             };
1466c3739801SMiguel Ojeda             // Implements only the methods; caller must invoke this from inside
1467c3739801SMiguel Ojeda             // an impl block.
1468c3739801SMiguel Ojeda             (@methods @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => {
1469c3739801SMiguel Ojeda                 fn with_passing_test_cases<F: Fn(Box<ReadOnly<Self>>)>(_f: F) {
1470c3739801SMiguel Ojeda                     $(
1471c3739801SMiguel Ojeda                         let bx = Box::<Self>::from($success_case);
1472c3739801SMiguel Ojeda                         let ro: Box<ReadOnly<_>> = {
1473c3739801SMiguel Ojeda                             let raw = Box::into_raw(bx);
1474c3739801SMiguel Ojeda                             // SAFETY: `ReadOnly<T>` has the same layout and bit
1475c3739801SMiguel Ojeda                             // validity as `T`.
1476c3739801SMiguel Ojeda                             #[allow(clippy::as_conversions)]
1477c3739801SMiguel Ojeda                             unsafe { Box::from_raw(raw as *mut _) }
1478c3739801SMiguel Ojeda                         };
1479c3739801SMiguel Ojeda                         _f(ro);
1480c3739801SMiguel Ojeda                     )*
1481c3739801SMiguel Ojeda                 }
1482c3739801SMiguel Ojeda 
1483c3739801SMiguel Ojeda                 fn with_failing_test_cases<F: Fn(&mut [u8])>(_f: F) {
1484c3739801SMiguel Ojeda                     $($(
1485c3739801SMiguel Ojeda                         let mut case = $failure_case;
1486c3739801SMiguel Ojeda                         _f(case.as_mut_bytes());
1487c3739801SMiguel Ojeda                     )*)?
1488c3739801SMiguel Ojeda                 }
1489c3739801SMiguel Ojeda             };
1490c3739801SMiguel Ojeda         }
1491c3739801SMiguel Ojeda 
1492c3739801SMiguel Ojeda         impl_try_from_bytes_testable_for_null_pointer_optimization!(
1493c3739801SMiguel Ojeda             Box<UnsafeCell<NotZerocopy>>,
1494c3739801SMiguel Ojeda             &'static UnsafeCell<NotZerocopy>,
1495c3739801SMiguel Ojeda             &'static mut UnsafeCell<NotZerocopy>,
1496c3739801SMiguel Ojeda             NonNull<UnsafeCell<NotZerocopy>>,
1497c3739801SMiguel Ojeda             fn(),
1498c3739801SMiguel Ojeda             FnManyArgs,
1499c3739801SMiguel Ojeda             extern "C" fn(),
1500c3739801SMiguel Ojeda             ECFnManyArgs
1501c3739801SMiguel Ojeda         );
1502c3739801SMiguel Ojeda 
1503c3739801SMiguel Ojeda         macro_rules! bx {
1504c3739801SMiguel Ojeda             ($e:expr) => {
1505c3739801SMiguel Ojeda                 Box::new($e)
1506c3739801SMiguel Ojeda             };
1507c3739801SMiguel Ojeda         }
1508c3739801SMiguel Ojeda 
1509c3739801SMiguel Ojeda         // Note that these impls are only for types which are not `FromBytes`.
1510c3739801SMiguel Ojeda         // `FromBytes` types are covered by a preceding blanket impl.
1511c3739801SMiguel Ojeda         impl_try_from_bytes_testable!(
1512c3739801SMiguel Ojeda             bool => @success true, false,
1513c3739801SMiguel Ojeda                     @failure 2u8, 3u8, 0xFFu8;
1514c3739801SMiguel Ojeda             char => @success '\u{0}', '\u{D7FF}', '\u{E000}', '\u{10FFFF}',
1515c3739801SMiguel Ojeda                     @failure 0xD800u32, 0xDFFFu32, 0x110000u32;
1516c3739801SMiguel Ojeda             str  => @success "", "hello", "❤️����������",
1517c3739801SMiguel Ojeda                     @failure [0, 159, 146, 150];
1518c3739801SMiguel Ojeda             [u8] => @success vec![].into_boxed_slice(), vec![0, 1, 2].into_boxed_slice();
1519c3739801SMiguel Ojeda             NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32,
1520c3739801SMiguel Ojeda             NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128,
1521c3739801SMiguel Ojeda             NonZeroUsize, NonZeroIsize
1522c3739801SMiguel Ojeda                 => @success Self::new(1).unwrap(),
1523c3739801SMiguel Ojeda                    // Doing this instead of `0` ensures that we always satisfy
1524c3739801SMiguel Ojeda                    // the size and alignment requirements of `Self` (whereas `0`
1525c3739801SMiguel Ojeda                    // may be any integer type with a different size or alignment
1526c3739801SMiguel Ojeda                    // than some `NonZeroXxx` types).
1527c3739801SMiguel Ojeda                    @failure Option::<Self>::None;
1528c3739801SMiguel Ojeda             [bool; 0] => @success [];
1529c3739801SMiguel Ojeda             [bool; 1]
1530c3739801SMiguel Ojeda                 => @success [true], [false],
1531c3739801SMiguel Ojeda                    @failure [2u8], [3u8], [0xFFu8];
1532c3739801SMiguel Ojeda             [bool]
1533c3739801SMiguel Ojeda                 => @success vec![true, false].into_boxed_slice(), vec![false, true].into_boxed_slice(),
1534c3739801SMiguel Ojeda                     @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8];
1535c3739801SMiguel Ojeda             Unalign<bool>
1536c3739801SMiguel Ojeda                 => @success Unalign::new(false), Unalign::new(true),
1537c3739801SMiguel Ojeda                    @failure 2u8, 0xFFu8;
1538c3739801SMiguel Ojeda             ManuallyDrop<bool>
1539c3739801SMiguel Ojeda                 => @success ManuallyDrop::new(false), ManuallyDrop::new(true),
1540c3739801SMiguel Ojeda                    @failure 2u8, 0xFFu8;
1541c3739801SMiguel Ojeda             ManuallyDrop<[u8]>
1542c3739801SMiguel Ojeda                 => @success bx!(ManuallyDrop::new([])), bx!(ManuallyDrop::new([0u8])), bx!(ManuallyDrop::new([0u8, 1u8]));
1543c3739801SMiguel Ojeda             ManuallyDrop<[bool]>
1544c3739801SMiguel Ojeda                 => @success bx!(ManuallyDrop::new([])), bx!(ManuallyDrop::new([false])), bx!(ManuallyDrop::new([false, true])),
1545c3739801SMiguel Ojeda                    @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8];
1546c3739801SMiguel Ojeda             ManuallyDrop<[UnsafeCell<u8>]>
1547c3739801SMiguel Ojeda                 => @success bx!(ManuallyDrop::new([UnsafeCell::new(0)])), bx!(ManuallyDrop::new([UnsafeCell::new(0), UnsafeCell::new(1)]));
1548c3739801SMiguel Ojeda             ManuallyDrop<[UnsafeCell<bool>]>
1549c3739801SMiguel Ojeda                 => @success bx!(ManuallyDrop::new([UnsafeCell::new(false)])), bx!(ManuallyDrop::new([UnsafeCell::new(false), UnsafeCell::new(true)])),
1550c3739801SMiguel Ojeda                 @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8];
1551c3739801SMiguel Ojeda             Wrapping<bool>
1552c3739801SMiguel Ojeda                 => @success Wrapping(false), Wrapping(true),
1553c3739801SMiguel Ojeda                     @failure 2u8, 0xFFu8;
1554c3739801SMiguel Ojeda             *const NotZerocopy
1555c3739801SMiguel Ojeda                 => @success ptr::null::<NotZerocopy>(),
1556c3739801SMiguel Ojeda                    @failure [0x01; mem::size_of::<*const NotZerocopy>()];
1557c3739801SMiguel Ojeda             *mut NotZerocopy
1558c3739801SMiguel Ojeda                 => @success ptr::null_mut::<NotZerocopy>(),
1559c3739801SMiguel Ojeda                    @failure [0x01; mem::size_of::<*mut NotZerocopy>()];
1560c3739801SMiguel Ojeda         );
1561c3739801SMiguel Ojeda 
1562c3739801SMiguel Ojeda         // Use the trick described in [1] to allow us to call methods
1563c3739801SMiguel Ojeda         // conditional on certain trait bounds.
1564c3739801SMiguel Ojeda         //
1565c3739801SMiguel Ojeda         // In all of these cases, methods return `Option<R>`, where `R` is the
1566c3739801SMiguel Ojeda         // return type of the method we're conditionally calling. The "real"
1567c3739801SMiguel Ojeda         // implementations (the ones defined in traits using `&self`) return
1568c3739801SMiguel Ojeda         // `Some`, and the default implementations (the ones defined as inherent
1569c3739801SMiguel Ojeda         // methods using `&mut self`) return `None`.
1570c3739801SMiguel Ojeda         //
1571c3739801SMiguel Ojeda         // [1] https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md
1572c3739801SMiguel Ojeda         mod autoref_trick {
1573c3739801SMiguel Ojeda             use super::*;
1574c3739801SMiguel Ojeda 
1575c3739801SMiguel Ojeda             pub(super) struct AutorefWrapper<T: ?Sized>(pub(super) PhantomData<T>);
1576c3739801SMiguel Ojeda 
1577c3739801SMiguel Ojeda             pub(super) trait TestIsBitValidShared<T: ?Sized> {
1578c3739801SMiguel Ojeda                 #[allow(clippy::needless_lifetimes)]
1579c3739801SMiguel Ojeda                 fn test_is_bit_valid_shared<'ptr>(&self, candidate: Maybe<'ptr, T>)
1580c3739801SMiguel Ojeda                     -> Option<bool>;
1581c3739801SMiguel Ojeda             }
1582c3739801SMiguel Ojeda 
1583c3739801SMiguel Ojeda             impl<T: TryFromBytes + Immutable + ?Sized> TestIsBitValidShared<T> for AutorefWrapper<T> {
1584c3739801SMiguel Ojeda                 #[allow(clippy::needless_lifetimes)]
1585c3739801SMiguel Ojeda                 fn test_is_bit_valid_shared<'ptr>(
1586c3739801SMiguel Ojeda                     &self,
1587c3739801SMiguel Ojeda                     candidate: Maybe<'ptr, T>,
1588c3739801SMiguel Ojeda                 ) -> Option<bool> {
1589c3739801SMiguel Ojeda                     Some(T::is_bit_valid(candidate))
1590c3739801SMiguel Ojeda                 }
1591c3739801SMiguel Ojeda             }
1592c3739801SMiguel Ojeda 
1593c3739801SMiguel Ojeda             pub(super) trait TestTryFromRef<T: ?Sized> {
1594c3739801SMiguel Ojeda                 #[allow(clippy::needless_lifetimes)]
1595c3739801SMiguel Ojeda                 fn test_try_from_ref<'bytes>(
1596c3739801SMiguel Ojeda                     &self,
1597c3739801SMiguel Ojeda                     bytes: &'bytes [u8],
1598c3739801SMiguel Ojeda                 ) -> Option<Option<&'bytes T>>;
1599c3739801SMiguel Ojeda             }
1600c3739801SMiguel Ojeda 
1601c3739801SMiguel Ojeda             impl<T: TryFromBytes + Immutable + KnownLayout + ?Sized> TestTryFromRef<T> for AutorefWrapper<T> {
1602c3739801SMiguel Ojeda                 #[allow(clippy::needless_lifetimes)]
1603c3739801SMiguel Ojeda                 fn test_try_from_ref<'bytes>(
1604c3739801SMiguel Ojeda                     &self,
1605c3739801SMiguel Ojeda                     bytes: &'bytes [u8],
1606c3739801SMiguel Ojeda                 ) -> Option<Option<&'bytes T>> {
1607c3739801SMiguel Ojeda                     Some(T::try_ref_from_bytes(bytes).ok())
1608c3739801SMiguel Ojeda                 }
1609c3739801SMiguel Ojeda             }
1610c3739801SMiguel Ojeda 
1611c3739801SMiguel Ojeda             pub(super) trait TestTryFromMut<T: ?Sized> {
1612c3739801SMiguel Ojeda                 #[allow(clippy::needless_lifetimes)]
1613c3739801SMiguel Ojeda                 fn test_try_from_mut<'bytes>(
1614c3739801SMiguel Ojeda                     &self,
1615c3739801SMiguel Ojeda                     bytes: &'bytes mut [u8],
1616c3739801SMiguel Ojeda                 ) -> Option<Option<&'bytes mut T>>;
1617c3739801SMiguel Ojeda             }
1618c3739801SMiguel Ojeda 
1619c3739801SMiguel Ojeda             impl<T: TryFromBytes + IntoBytes + KnownLayout + ?Sized> TestTryFromMut<T> for AutorefWrapper<T> {
1620c3739801SMiguel Ojeda                 #[allow(clippy::needless_lifetimes)]
1621c3739801SMiguel Ojeda                 fn test_try_from_mut<'bytes>(
1622c3739801SMiguel Ojeda                     &self,
1623c3739801SMiguel Ojeda                     bytes: &'bytes mut [u8],
1624c3739801SMiguel Ojeda                 ) -> Option<Option<&'bytes mut T>> {
1625c3739801SMiguel Ojeda                     Some(T::try_mut_from_bytes(bytes).ok())
1626c3739801SMiguel Ojeda                 }
1627c3739801SMiguel Ojeda             }
1628c3739801SMiguel Ojeda 
1629c3739801SMiguel Ojeda             pub(super) trait TestTryReadFrom<T> {
1630c3739801SMiguel Ojeda                 fn test_try_read_from(&self, bytes: &[u8]) -> Option<Option<T>>;
1631c3739801SMiguel Ojeda             }
1632c3739801SMiguel Ojeda 
1633c3739801SMiguel Ojeda             impl<T: TryFromBytes> TestTryReadFrom<T> for AutorefWrapper<T> {
1634c3739801SMiguel Ojeda                 fn test_try_read_from(&self, bytes: &[u8]) -> Option<Option<T>> {
1635c3739801SMiguel Ojeda                     Some(T::try_read_from_bytes(bytes).ok())
1636c3739801SMiguel Ojeda                 }
1637c3739801SMiguel Ojeda             }
1638c3739801SMiguel Ojeda 
1639c3739801SMiguel Ojeda             pub(super) trait TestAsBytes<T: ?Sized> {
1640c3739801SMiguel Ojeda                 #[allow(clippy::needless_lifetimes)]
1641c3739801SMiguel Ojeda                 fn test_as_bytes<'slf, 't>(&'slf self, t: &'t ReadOnly<T>) -> Option<&'t [u8]>;
1642c3739801SMiguel Ojeda             }
1643c3739801SMiguel Ojeda 
1644c3739801SMiguel Ojeda             impl<T: IntoBytes + Immutable + ?Sized> TestAsBytes<T> for AutorefWrapper<T> {
1645c3739801SMiguel Ojeda                 #[allow(clippy::needless_lifetimes)]
1646c3739801SMiguel Ojeda                 fn test_as_bytes<'slf, 't>(&'slf self, t: &'t ReadOnly<T>) -> Option<&'t [u8]> {
1647c3739801SMiguel Ojeda                     Some(t.as_bytes())
1648c3739801SMiguel Ojeda                 }
1649c3739801SMiguel Ojeda             }
1650c3739801SMiguel Ojeda         }
1651c3739801SMiguel Ojeda 
1652c3739801SMiguel Ojeda         use autoref_trick::*;
1653c3739801SMiguel Ojeda 
1654c3739801SMiguel Ojeda         // Asserts that `$ty` is one of a list of types which are allowed to not
1655c3739801SMiguel Ojeda         // provide a "real" implementation for `$fn_name`. Since the
1656c3739801SMiguel Ojeda         // `autoref_trick` machinery fails silently, this allows us to ensure
1657c3739801SMiguel Ojeda         // that the "default" impls are only being used for types which we
1658c3739801SMiguel Ojeda         // expect.
1659c3739801SMiguel Ojeda         //
1660c3739801SMiguel Ojeda         // Note that, since this is a runtime test, it is possible to have an
1661c3739801SMiguel Ojeda         // allowlist which is too restrictive if the function in question is
1662c3739801SMiguel Ojeda         // never called for a particular type. For example, if `as_bytes` is not
1663c3739801SMiguel Ojeda         // supported for a particular type, and so `test_as_bytes` returns
1664c3739801SMiguel Ojeda         // `None`, methods such as `test_try_from_ref` may never be called for
1665c3739801SMiguel Ojeda         // that type. As a result, it's possible that, for example, adding
1666c3739801SMiguel Ojeda         // `as_bytes` support for a type would cause other allowlist assertions
1667c3739801SMiguel Ojeda         // to fail. This means that allowlist assertion failures should not
1668c3739801SMiguel Ojeda         // automatically be taken as a sign of a bug.
1669c3739801SMiguel Ojeda         macro_rules! assert_on_allowlist {
1670c3739801SMiguel Ojeda             ($fn_name:ident($ty:ty) $(: $($tys:ty),*)?) => {{
1671c3739801SMiguel Ojeda                 use core::any::TypeId;
1672c3739801SMiguel Ojeda 
1673c3739801SMiguel Ojeda                 let allowlist: &[TypeId] = &[ $($(TypeId::of::<$tys>()),*)? ];
1674c3739801SMiguel Ojeda                 let allowlist_names: &[&str] = &[ $($(stringify!($tys)),*)? ];
1675c3739801SMiguel Ojeda 
1676c3739801SMiguel Ojeda                 let id = TypeId::of::<$ty>();
1677c3739801SMiguel Ojeda                 assert!(allowlist.contains(&id), "{} is not on allowlist for {}: {:?}", stringify!($ty), stringify!($fn_name), allowlist_names);
1678c3739801SMiguel Ojeda             }};
1679c3739801SMiguel Ojeda         }
1680c3739801SMiguel Ojeda 
1681c3739801SMiguel Ojeda         // Asserts that `$ty` implements any `$trait` and doesn't implement any
1682c3739801SMiguel Ojeda         // `!$trait`. Note that all `$trait`s must come before any `!$trait`s.
1683c3739801SMiguel Ojeda         //
1684c3739801SMiguel Ojeda         // For `T: TryFromBytes`, uses `TryFromBytesTestable` to test success
1685c3739801SMiguel Ojeda         // and failure cases.
1686c3739801SMiguel Ojeda         macro_rules! assert_impls {
1687c3739801SMiguel Ojeda             ($ty:ty: TryFromBytes) => {
1688c3739801SMiguel Ojeda                 // "Default" implementations that match the "real"
1689c3739801SMiguel Ojeda                 // implementations defined in the `autoref_trick` module above.
1690c3739801SMiguel Ojeda                 #[allow(unused, non_local_definitions)]
1691c3739801SMiguel Ojeda                 impl AutorefWrapper<$ty> {
1692c3739801SMiguel Ojeda                     #[allow(clippy::needless_lifetimes)]
1693c3739801SMiguel Ojeda                     fn test_is_bit_valid_shared<'ptr>(
1694c3739801SMiguel Ojeda                         &mut self,
1695c3739801SMiguel Ojeda                         candidate: Maybe<'ptr, $ty>,
1696c3739801SMiguel Ojeda                     ) -> Option<bool> {
1697c3739801SMiguel Ojeda                         assert_on_allowlist!(
1698c3739801SMiguel Ojeda                             test_is_bit_valid_shared($ty):
1699c3739801SMiguel Ojeda                             ManuallyDrop<UnsafeCell<()>>,
1700c3739801SMiguel Ojeda                             ManuallyDrop<[UnsafeCell<u8>]>,
1701c3739801SMiguel Ojeda                             ManuallyDrop<[UnsafeCell<bool>]>,
1702c3739801SMiguel Ojeda                             CoreMaybeUninit<NotZerocopy>,
1703c3739801SMiguel Ojeda                             CoreMaybeUninit<UnsafeCell<()>>,
1704c3739801SMiguel Ojeda                             Wrapping<UnsafeCell<()>>
1705c3739801SMiguel Ojeda                         );
1706c3739801SMiguel Ojeda 
1707c3739801SMiguel Ojeda                         None
1708c3739801SMiguel Ojeda                     }
1709c3739801SMiguel Ojeda 
1710c3739801SMiguel Ojeda                     #[allow(clippy::needless_lifetimes)]
1711c3739801SMiguel Ojeda                     fn test_try_from_ref<'bytes>(&mut self, _bytes: &'bytes [u8]) -> Option<Option<&'bytes $ty>> {
1712c3739801SMiguel Ojeda                         assert_on_allowlist!(
1713c3739801SMiguel Ojeda                             test_try_from_ref($ty):
1714c3739801SMiguel Ojeda                             ManuallyDrop<[UnsafeCell<bool>]>
1715c3739801SMiguel Ojeda                         );
1716c3739801SMiguel Ojeda 
1717c3739801SMiguel Ojeda                         None
1718c3739801SMiguel Ojeda                     }
1719c3739801SMiguel Ojeda 
1720c3739801SMiguel Ojeda                     #[allow(clippy::needless_lifetimes)]
1721c3739801SMiguel Ojeda                     fn test_try_from_mut<'bytes>(&mut self, _bytes: &'bytes mut [u8]) -> Option<Option<&'bytes mut $ty>> {
1722c3739801SMiguel Ojeda                         assert_on_allowlist!(
1723c3739801SMiguel Ojeda                             test_try_from_mut($ty):
1724c3739801SMiguel Ojeda                             Option<Box<UnsafeCell<NotZerocopy>>>,
1725c3739801SMiguel Ojeda                             Option<&'static UnsafeCell<NotZerocopy>>,
1726c3739801SMiguel Ojeda                             Option<&'static mut UnsafeCell<NotZerocopy>>,
1727c3739801SMiguel Ojeda                             Option<NonNull<UnsafeCell<NotZerocopy>>>,
1728c3739801SMiguel Ojeda                             Option<fn()>,
1729c3739801SMiguel Ojeda                             Option<FnManyArgs>,
1730c3739801SMiguel Ojeda                             Option<extern "C" fn()>,
1731c3739801SMiguel Ojeda                             Option<ECFnManyArgs>,
1732c3739801SMiguel Ojeda                             *const NotZerocopy,
1733c3739801SMiguel Ojeda                             *mut NotZerocopy
1734c3739801SMiguel Ojeda                         );
1735c3739801SMiguel Ojeda 
1736c3739801SMiguel Ojeda                         None
1737c3739801SMiguel Ojeda                     }
1738c3739801SMiguel Ojeda 
1739c3739801SMiguel Ojeda                     fn test_try_read_from(&mut self, _bytes: &[u8]) -> Option<Option<&$ty>> {
1740c3739801SMiguel Ojeda                         assert_on_allowlist!(
1741c3739801SMiguel Ojeda                             test_try_read_from($ty):
1742c3739801SMiguel Ojeda                             str,
1743c3739801SMiguel Ojeda                             ManuallyDrop<[u8]>,
1744c3739801SMiguel Ojeda                             ManuallyDrop<[bool]>,
1745c3739801SMiguel Ojeda                             ManuallyDrop<[UnsafeCell<bool>]>,
1746c3739801SMiguel Ojeda                             [u8],
1747c3739801SMiguel Ojeda                             [bool]
1748c3739801SMiguel Ojeda                         );
1749c3739801SMiguel Ojeda 
1750c3739801SMiguel Ojeda                         None
1751c3739801SMiguel Ojeda                     }
1752c3739801SMiguel Ojeda 
1753c3739801SMiguel Ojeda                     fn test_as_bytes(&mut self, _t: &ReadOnly<$ty>) -> Option<&[u8]> {
1754c3739801SMiguel Ojeda                         assert_on_allowlist!(
1755c3739801SMiguel Ojeda                             test_as_bytes($ty):
1756c3739801SMiguel Ojeda                             Option<&'static UnsafeCell<NotZerocopy>>,
1757c3739801SMiguel Ojeda                             Option<&'static mut UnsafeCell<NotZerocopy>>,
1758c3739801SMiguel Ojeda                             Option<NonNull<UnsafeCell<NotZerocopy>>>,
1759c3739801SMiguel Ojeda                             Option<Box<UnsafeCell<NotZerocopy>>>,
1760c3739801SMiguel Ojeda                             Option<fn()>,
1761c3739801SMiguel Ojeda                             Option<FnManyArgs>,
1762c3739801SMiguel Ojeda                             Option<extern "C" fn()>,
1763c3739801SMiguel Ojeda                             Option<ECFnManyArgs>,
1764c3739801SMiguel Ojeda                             CoreMaybeUninit<u8>,
1765c3739801SMiguel Ojeda                             CoreMaybeUninit<NotZerocopy>,
1766c3739801SMiguel Ojeda                             CoreMaybeUninit<UnsafeCell<()>>,
1767c3739801SMiguel Ojeda                             ManuallyDrop<UnsafeCell<()>>,
1768c3739801SMiguel Ojeda                             ManuallyDrop<[UnsafeCell<u8>]>,
1769c3739801SMiguel Ojeda                             ManuallyDrop<[UnsafeCell<bool>]>,
1770c3739801SMiguel Ojeda                             Wrapping<UnsafeCell<()>>,
1771c3739801SMiguel Ojeda                             *const NotZerocopy,
1772c3739801SMiguel Ojeda                             *mut NotZerocopy
1773c3739801SMiguel Ojeda                         );
1774c3739801SMiguel Ojeda 
1775c3739801SMiguel Ojeda                         None
1776c3739801SMiguel Ojeda                     }
1777c3739801SMiguel Ojeda                 }
1778c3739801SMiguel Ojeda 
1779c3739801SMiguel Ojeda                 <$ty as TryFromBytesTestable>::with_passing_test_cases(|mut val| {
1780c3739801SMiguel Ojeda                     // FIXME(#494): These tests only get exercised for types
1781c3739801SMiguel Ojeda                     // which are `IntoBytes`. Once we implement #494, we should
1782c3739801SMiguel Ojeda                     // be able to support non-`IntoBytes` types by zeroing
1783c3739801SMiguel Ojeda                     // padding.
1784c3739801SMiguel Ojeda 
1785c3739801SMiguel Ojeda                     // We define `w` and `ww` since, in the case of the inherent
1786c3739801SMiguel Ojeda                     // methods, Rust thinks they're both borrowed mutably at the
1787c3739801SMiguel Ojeda                     // same time (given how we use them below). If we just
1788c3739801SMiguel Ojeda                     // defined a single `w` and used it for multiple operations,
1789c3739801SMiguel Ojeda                     // this would conflict.
1790c3739801SMiguel Ojeda                     //
1791c3739801SMiguel Ojeda                     // We `#[allow(unused_mut]` for the cases where the "real"
1792c3739801SMiguel Ojeda                     // impls are used, which take `&self`.
1793c3739801SMiguel Ojeda                     #[allow(unused_mut)]
1794c3739801SMiguel Ojeda                     let (mut w, mut ww) = (AutorefWrapper::<$ty>(PhantomData), AutorefWrapper::<$ty>(PhantomData));
1795c3739801SMiguel Ojeda 
1796c3739801SMiguel Ojeda                     let c = Ptr::from_ref(&*val);
1797c3739801SMiguel Ojeda                     let c = c.forget_aligned();
1798c3739801SMiguel Ojeda                     // SAFETY: FIXME(#899): This is unsound. `$ty` is not
1799c3739801SMiguel Ojeda                     // necessarily `IntoBytes`, but that's the corner we've
1800c3739801SMiguel Ojeda                     // backed ourselves into by using `Ptr::from_ref`.
1801c3739801SMiguel Ojeda                     let c = unsafe { c.assume_initialized() };
1802c3739801SMiguel Ojeda                     let res = w.test_is_bit_valid_shared(c);
1803c3739801SMiguel Ojeda                     if let Some(res) = res {
1804c3739801SMiguel Ojeda                         assert!(res, "{}::is_bit_valid (shared `Ptr`): got false, expected true", stringify!($ty));
1805c3739801SMiguel Ojeda                     }
1806c3739801SMiguel Ojeda 
1807c3739801SMiguel Ojeda                     let c = Ptr::from_mut(&mut *val);
1808c3739801SMiguel Ojeda                     let c = c.forget_aligned();
1809c3739801SMiguel Ojeda                     // SAFETY: FIXME(#899): This is unsound. `$ty` is not
1810c3739801SMiguel Ojeda                     // necessarily `IntoBytes`, but that's the corner we've
1811c3739801SMiguel Ojeda                     // backed ourselves into by using `Ptr::from_ref`.
1812c3739801SMiguel Ojeda                     let mut c = unsafe { c.assume_initialized() };
1813c3739801SMiguel Ojeda                     let res = <$ty as TryFromBytes>::is_bit_valid(c.reborrow_shared());
1814c3739801SMiguel Ojeda                     assert!(res, "{}::is_bit_valid (exclusive `Ptr`): got false, expected true", stringify!($ty));
1815c3739801SMiguel Ojeda 
1816c3739801SMiguel Ojeda                     // `bytes` is `Some(val.as_bytes())` if `$ty: IntoBytes +
1817c3739801SMiguel Ojeda                     // Immutable` and `None` otherwise.
1818c3739801SMiguel Ojeda                     let bytes = w.test_as_bytes(&*val);
1819c3739801SMiguel Ojeda 
1820c3739801SMiguel Ojeda                     // The inner closure returns
1821c3739801SMiguel Ojeda                     // `Some($ty::try_ref_from_bytes(bytes))` if `$ty:
1822c3739801SMiguel Ojeda                     // Immutable` and `None` otherwise.
1823c3739801SMiguel Ojeda                     let res = bytes.and_then(|bytes| ww.test_try_from_ref(bytes));
1824c3739801SMiguel Ojeda                     if let Some(res) = res {
1825c3739801SMiguel Ojeda                         assert!(res.is_some(), "{}::try_ref_from_bytes: got `None`, expected `Some`", stringify!($ty));
1826c3739801SMiguel Ojeda                     }
1827c3739801SMiguel Ojeda 
1828c3739801SMiguel Ojeda                     if let Some(bytes) = bytes {
1829c3739801SMiguel Ojeda                         // We need to get a mutable byte slice, and so we clone
1830c3739801SMiguel Ojeda                         // into a `Vec`. However, we also need these bytes to
1831c3739801SMiguel Ojeda                         // satisfy `$ty`'s alignment requirement, which isn't
1832c3739801SMiguel Ojeda                         // guaranteed for `Vec<u8>`. In order to get around
1833c3739801SMiguel Ojeda                         // this, we create a `Vec` which is twice as long as we
1834c3739801SMiguel Ojeda                         // need. There is guaranteed to be an aligned byte range
1835c3739801SMiguel Ojeda                         // of size `size_of_val(val)` within that range.
1836c3739801SMiguel Ojeda                         let val = &*val;
1837c3739801SMiguel Ojeda                         let size = mem::size_of_val(val);
1838c3739801SMiguel Ojeda                         let align = mem::align_of_val(val);
1839c3739801SMiguel Ojeda 
1840c3739801SMiguel Ojeda                         let mut vec = bytes.to_vec();
1841c3739801SMiguel Ojeda                         vec.extend(bytes);
1842c3739801SMiguel Ojeda                         let slc = vec.as_slice();
1843c3739801SMiguel Ojeda                         let offset = slc.as_ptr().align_offset(align);
1844c3739801SMiguel Ojeda                         let bytes_mut = &mut vec.as_mut_slice()[offset..offset+size];
1845c3739801SMiguel Ojeda                         bytes_mut.copy_from_slice(bytes);
1846c3739801SMiguel Ojeda 
1847c3739801SMiguel Ojeda                         let res = ww.test_try_from_mut(bytes_mut);
1848c3739801SMiguel Ojeda                         if let Some(res) = res {
1849c3739801SMiguel Ojeda                             assert!(res.is_some(), "{}::try_mut_from_bytes: got `None`, expected `Some`", stringify!($ty));
1850c3739801SMiguel Ojeda                         }
1851c3739801SMiguel Ojeda                     }
1852c3739801SMiguel Ojeda 
1853c3739801SMiguel Ojeda                     let res = bytes.and_then(|bytes| ww.test_try_read_from(bytes));
1854c3739801SMiguel Ojeda                     if let Some(res) = res {
1855c3739801SMiguel Ojeda                         assert!(res.is_some(), "{}::try_read_from_bytes: got `None`, expected `Some`", stringify!($ty));
1856c3739801SMiguel Ojeda                     }
1857c3739801SMiguel Ojeda                 });
1858c3739801SMiguel Ojeda                 #[allow(clippy::as_conversions)]
1859c3739801SMiguel Ojeda                 <$ty as TryFromBytesTestable>::with_failing_test_cases(|c| {
1860c3739801SMiguel Ojeda                     #[allow(unused_mut)] // For cases where the "real" impls are used, which take `&self`.
1861c3739801SMiguel Ojeda                     let mut w = AutorefWrapper::<$ty>(PhantomData);
1862c3739801SMiguel Ojeda 
1863c3739801SMiguel Ojeda                     // This is `Some($ty::try_ref_from_bytes(c))` if `$ty:
1864c3739801SMiguel Ojeda                     // Immutable` and `None` otherwise.
1865c3739801SMiguel Ojeda                     let res = w.test_try_from_ref(c);
1866c3739801SMiguel Ojeda                     if let Some(res) = res {
1867c3739801SMiguel Ojeda                         assert!(res.is_none(), "{}::try_ref_from_bytes({:?}): got Some, expected None", stringify!($ty), c);
1868c3739801SMiguel Ojeda                     }
1869c3739801SMiguel Ojeda 
1870c3739801SMiguel Ojeda                     let res = w.test_try_from_mut(c);
1871c3739801SMiguel Ojeda                     if let Some(res) = res {
1872c3739801SMiguel Ojeda                         assert!(res.is_none(), "{}::try_mut_from_bytes({:?}): got Some, expected None", stringify!($ty), c);
1873c3739801SMiguel Ojeda                     }
1874c3739801SMiguel Ojeda 
1875c3739801SMiguel Ojeda 
1876c3739801SMiguel Ojeda                     let res = w.test_try_read_from(c);
1877c3739801SMiguel Ojeda                     if let Some(res) = res {
1878c3739801SMiguel Ojeda                         assert!(res.is_none(), "{}::try_read_from_bytes({:?}): got Some, expected None", stringify!($ty), c);
1879c3739801SMiguel Ojeda                     }
1880c3739801SMiguel Ojeda                 });
1881c3739801SMiguel Ojeda 
1882c3739801SMiguel Ojeda                 #[allow(dead_code)]
1883c3739801SMiguel Ojeda                 const _: () = { static_assertions::assert_impl_all!($ty: TryFromBytes); };
1884c3739801SMiguel Ojeda             };
1885c3739801SMiguel Ojeda             ($ty:ty: $trait:ident) => {
1886c3739801SMiguel Ojeda                 #[allow(dead_code)]
1887c3739801SMiguel Ojeda                 const _: () = { static_assertions::assert_impl_all!($ty: $trait); };
1888c3739801SMiguel Ojeda             };
1889c3739801SMiguel Ojeda             ($ty:ty: !$trait:ident) => {
1890c3739801SMiguel Ojeda                 #[allow(dead_code)]
1891c3739801SMiguel Ojeda                 const _: () = { static_assertions::assert_not_impl_any!($ty: $trait); };
1892c3739801SMiguel Ojeda             };
1893c3739801SMiguel Ojeda             ($ty:ty: $($trait:ident),* $(,)? $(!$negative_trait:ident),*) => {
1894c3739801SMiguel Ojeda                 $(
1895c3739801SMiguel Ojeda                     assert_impls!($ty: $trait);
1896c3739801SMiguel Ojeda                 )*
1897c3739801SMiguel Ojeda 
1898c3739801SMiguel Ojeda                 $(
1899c3739801SMiguel Ojeda                     assert_impls!($ty: !$negative_trait);
1900c3739801SMiguel Ojeda                 )*
1901c3739801SMiguel Ojeda             };
1902c3739801SMiguel Ojeda         }
1903c3739801SMiguel Ojeda 
1904c3739801SMiguel Ojeda         // NOTE: The negative impl assertions here are not necessarily
1905c3739801SMiguel Ojeda         // prescriptive. They merely serve as change detectors to make sure
1906c3739801SMiguel Ojeda         // we're aware of what trait impls are getting added with a given
1907c3739801SMiguel Ojeda         // change. Of course, some impls would be invalid (e.g., `bool:
1908c3739801SMiguel Ojeda         // FromBytes`), and so this change detection is very important.
1909c3739801SMiguel Ojeda 
1910c3739801SMiguel Ojeda         assert_impls!(
1911c3739801SMiguel Ojeda             (): KnownLayout,
1912c3739801SMiguel Ojeda             Immutable,
1913c3739801SMiguel Ojeda             TryFromBytes,
1914c3739801SMiguel Ojeda             FromZeros,
1915c3739801SMiguel Ojeda             FromBytes,
1916c3739801SMiguel Ojeda             IntoBytes,
1917c3739801SMiguel Ojeda             Unaligned
1918c3739801SMiguel Ojeda         );
1919c3739801SMiguel Ojeda         assert_impls!(
1920c3739801SMiguel Ojeda             u8: KnownLayout,
1921c3739801SMiguel Ojeda             Immutable,
1922c3739801SMiguel Ojeda             TryFromBytes,
1923c3739801SMiguel Ojeda             FromZeros,
1924c3739801SMiguel Ojeda             FromBytes,
1925c3739801SMiguel Ojeda             IntoBytes,
1926c3739801SMiguel Ojeda             Unaligned
1927c3739801SMiguel Ojeda         );
1928c3739801SMiguel Ojeda         assert_impls!(
1929c3739801SMiguel Ojeda             i8: KnownLayout,
1930c3739801SMiguel Ojeda             Immutable,
1931c3739801SMiguel Ojeda             TryFromBytes,
1932c3739801SMiguel Ojeda             FromZeros,
1933c3739801SMiguel Ojeda             FromBytes,
1934c3739801SMiguel Ojeda             IntoBytes,
1935c3739801SMiguel Ojeda             Unaligned
1936c3739801SMiguel Ojeda         );
1937c3739801SMiguel Ojeda         assert_impls!(
1938c3739801SMiguel Ojeda             u16: KnownLayout,
1939c3739801SMiguel Ojeda             Immutable,
1940c3739801SMiguel Ojeda             TryFromBytes,
1941c3739801SMiguel Ojeda             FromZeros,
1942c3739801SMiguel Ojeda             FromBytes,
1943c3739801SMiguel Ojeda             IntoBytes,
1944c3739801SMiguel Ojeda             !Unaligned
1945c3739801SMiguel Ojeda         );
1946c3739801SMiguel Ojeda         assert_impls!(
1947c3739801SMiguel Ojeda             i16: KnownLayout,
1948c3739801SMiguel Ojeda             Immutable,
1949c3739801SMiguel Ojeda             TryFromBytes,
1950c3739801SMiguel Ojeda             FromZeros,
1951c3739801SMiguel Ojeda             FromBytes,
1952c3739801SMiguel Ojeda             IntoBytes,
1953c3739801SMiguel Ojeda             !Unaligned
1954c3739801SMiguel Ojeda         );
1955c3739801SMiguel Ojeda         assert_impls!(
1956c3739801SMiguel Ojeda             u32: KnownLayout,
1957c3739801SMiguel Ojeda             Immutable,
1958c3739801SMiguel Ojeda             TryFromBytes,
1959c3739801SMiguel Ojeda             FromZeros,
1960c3739801SMiguel Ojeda             FromBytes,
1961c3739801SMiguel Ojeda             IntoBytes,
1962c3739801SMiguel Ojeda             !Unaligned
1963c3739801SMiguel Ojeda         );
1964c3739801SMiguel Ojeda         assert_impls!(
1965c3739801SMiguel Ojeda             i32: KnownLayout,
1966c3739801SMiguel Ojeda             Immutable,
1967c3739801SMiguel Ojeda             TryFromBytes,
1968c3739801SMiguel Ojeda             FromZeros,
1969c3739801SMiguel Ojeda             FromBytes,
1970c3739801SMiguel Ojeda             IntoBytes,
1971c3739801SMiguel Ojeda             !Unaligned
1972c3739801SMiguel Ojeda         );
1973c3739801SMiguel Ojeda         assert_impls!(
1974c3739801SMiguel Ojeda             u64: KnownLayout,
1975c3739801SMiguel Ojeda             Immutable,
1976c3739801SMiguel Ojeda             TryFromBytes,
1977c3739801SMiguel Ojeda             FromZeros,
1978c3739801SMiguel Ojeda             FromBytes,
1979c3739801SMiguel Ojeda             IntoBytes,
1980c3739801SMiguel Ojeda             !Unaligned
1981c3739801SMiguel Ojeda         );
1982c3739801SMiguel Ojeda         assert_impls!(
1983c3739801SMiguel Ojeda             i64: KnownLayout,
1984c3739801SMiguel Ojeda             Immutable,
1985c3739801SMiguel Ojeda             TryFromBytes,
1986c3739801SMiguel Ojeda             FromZeros,
1987c3739801SMiguel Ojeda             FromBytes,
1988c3739801SMiguel Ojeda             IntoBytes,
1989c3739801SMiguel Ojeda             !Unaligned
1990c3739801SMiguel Ojeda         );
1991c3739801SMiguel Ojeda         assert_impls!(
1992c3739801SMiguel Ojeda             u128: KnownLayout,
1993c3739801SMiguel Ojeda             Immutable,
1994c3739801SMiguel Ojeda             TryFromBytes,
1995c3739801SMiguel Ojeda             FromZeros,
1996c3739801SMiguel Ojeda             FromBytes,
1997c3739801SMiguel Ojeda             IntoBytes,
1998c3739801SMiguel Ojeda             !Unaligned
1999c3739801SMiguel Ojeda         );
2000c3739801SMiguel Ojeda         assert_impls!(
2001c3739801SMiguel Ojeda             i128: KnownLayout,
2002c3739801SMiguel Ojeda             Immutable,
2003c3739801SMiguel Ojeda             TryFromBytes,
2004c3739801SMiguel Ojeda             FromZeros,
2005c3739801SMiguel Ojeda             FromBytes,
2006c3739801SMiguel Ojeda             IntoBytes,
2007c3739801SMiguel Ojeda             !Unaligned
2008c3739801SMiguel Ojeda         );
2009c3739801SMiguel Ojeda         assert_impls!(
2010c3739801SMiguel Ojeda             usize: KnownLayout,
2011c3739801SMiguel Ojeda             Immutable,
2012c3739801SMiguel Ojeda             TryFromBytes,
2013c3739801SMiguel Ojeda             FromZeros,
2014c3739801SMiguel Ojeda             FromBytes,
2015c3739801SMiguel Ojeda             IntoBytes,
2016c3739801SMiguel Ojeda             !Unaligned
2017c3739801SMiguel Ojeda         );
2018c3739801SMiguel Ojeda         assert_impls!(
2019c3739801SMiguel Ojeda             isize: KnownLayout,
2020c3739801SMiguel Ojeda             Immutable,
2021c3739801SMiguel Ojeda             TryFromBytes,
2022c3739801SMiguel Ojeda             FromZeros,
2023c3739801SMiguel Ojeda             FromBytes,
2024c3739801SMiguel Ojeda             IntoBytes,
2025c3739801SMiguel Ojeda             !Unaligned
2026c3739801SMiguel Ojeda         );
2027c3739801SMiguel Ojeda         #[cfg(feature = "float-nightly")]
2028c3739801SMiguel Ojeda         assert_impls!(
2029c3739801SMiguel Ojeda             f16: KnownLayout,
2030c3739801SMiguel Ojeda             Immutable,
2031c3739801SMiguel Ojeda             TryFromBytes,
2032c3739801SMiguel Ojeda             FromZeros,
2033c3739801SMiguel Ojeda             FromBytes,
2034c3739801SMiguel Ojeda             IntoBytes,
2035c3739801SMiguel Ojeda             !Unaligned
2036c3739801SMiguel Ojeda         );
2037c3739801SMiguel Ojeda         assert_impls!(
2038c3739801SMiguel Ojeda             f32: KnownLayout,
2039c3739801SMiguel Ojeda             Immutable,
2040c3739801SMiguel Ojeda             TryFromBytes,
2041c3739801SMiguel Ojeda             FromZeros,
2042c3739801SMiguel Ojeda             FromBytes,
2043c3739801SMiguel Ojeda             IntoBytes,
2044c3739801SMiguel Ojeda             !Unaligned
2045c3739801SMiguel Ojeda         );
2046c3739801SMiguel Ojeda         assert_impls!(
2047c3739801SMiguel Ojeda             f64: KnownLayout,
2048c3739801SMiguel Ojeda             Immutable,
2049c3739801SMiguel Ojeda             TryFromBytes,
2050c3739801SMiguel Ojeda             FromZeros,
2051c3739801SMiguel Ojeda             FromBytes,
2052c3739801SMiguel Ojeda             IntoBytes,
2053c3739801SMiguel Ojeda             !Unaligned
2054c3739801SMiguel Ojeda         );
2055c3739801SMiguel Ojeda         #[cfg(feature = "float-nightly")]
2056c3739801SMiguel Ojeda         assert_impls!(
2057c3739801SMiguel Ojeda             f128: KnownLayout,
2058c3739801SMiguel Ojeda             Immutable,
2059c3739801SMiguel Ojeda             TryFromBytes,
2060c3739801SMiguel Ojeda             FromZeros,
2061c3739801SMiguel Ojeda             FromBytes,
2062c3739801SMiguel Ojeda             IntoBytes,
2063c3739801SMiguel Ojeda             !Unaligned
2064c3739801SMiguel Ojeda         );
2065c3739801SMiguel Ojeda         assert_impls!(
2066c3739801SMiguel Ojeda             bool: KnownLayout,
2067c3739801SMiguel Ojeda             Immutable,
2068c3739801SMiguel Ojeda             TryFromBytes,
2069c3739801SMiguel Ojeda             FromZeros,
2070c3739801SMiguel Ojeda             IntoBytes,
2071c3739801SMiguel Ojeda             Unaligned,
2072c3739801SMiguel Ojeda             !FromBytes
2073c3739801SMiguel Ojeda         );
2074c3739801SMiguel Ojeda         assert_impls!(
2075c3739801SMiguel Ojeda             char: KnownLayout,
2076c3739801SMiguel Ojeda             Immutable,
2077c3739801SMiguel Ojeda             TryFromBytes,
2078c3739801SMiguel Ojeda             FromZeros,
2079c3739801SMiguel Ojeda             IntoBytes,
2080c3739801SMiguel Ojeda             !FromBytes,
2081c3739801SMiguel Ojeda             !Unaligned
2082c3739801SMiguel Ojeda         );
2083c3739801SMiguel Ojeda         assert_impls!(
2084c3739801SMiguel Ojeda             str: KnownLayout,
2085c3739801SMiguel Ojeda             Immutable,
2086c3739801SMiguel Ojeda             TryFromBytes,
2087c3739801SMiguel Ojeda             FromZeros,
2088c3739801SMiguel Ojeda             IntoBytes,
2089c3739801SMiguel Ojeda             Unaligned,
2090c3739801SMiguel Ojeda             !FromBytes
2091c3739801SMiguel Ojeda         );
2092c3739801SMiguel Ojeda 
2093c3739801SMiguel Ojeda         assert_impls!(
2094c3739801SMiguel Ojeda             NonZeroU8: KnownLayout,
2095c3739801SMiguel Ojeda             Immutable,
2096c3739801SMiguel Ojeda             TryFromBytes,
2097c3739801SMiguel Ojeda             IntoBytes,
2098c3739801SMiguel Ojeda             Unaligned,
2099c3739801SMiguel Ojeda             !FromZeros,
2100c3739801SMiguel Ojeda             !FromBytes
2101c3739801SMiguel Ojeda         );
2102c3739801SMiguel Ojeda         assert_impls!(
2103c3739801SMiguel Ojeda             NonZeroI8: KnownLayout,
2104c3739801SMiguel Ojeda             Immutable,
2105c3739801SMiguel Ojeda             TryFromBytes,
2106c3739801SMiguel Ojeda             IntoBytes,
2107c3739801SMiguel Ojeda             Unaligned,
2108c3739801SMiguel Ojeda             !FromZeros,
2109c3739801SMiguel Ojeda             !FromBytes
2110c3739801SMiguel Ojeda         );
2111c3739801SMiguel Ojeda         assert_impls!(
2112c3739801SMiguel Ojeda             NonZeroU16: KnownLayout,
2113c3739801SMiguel Ojeda             Immutable,
2114c3739801SMiguel Ojeda             TryFromBytes,
2115c3739801SMiguel Ojeda             IntoBytes,
2116c3739801SMiguel Ojeda             !FromBytes,
2117c3739801SMiguel Ojeda             !Unaligned
2118c3739801SMiguel Ojeda         );
2119c3739801SMiguel Ojeda         assert_impls!(
2120c3739801SMiguel Ojeda             NonZeroI16: KnownLayout,
2121c3739801SMiguel Ojeda             Immutable,
2122c3739801SMiguel Ojeda             TryFromBytes,
2123c3739801SMiguel Ojeda             IntoBytes,
2124c3739801SMiguel Ojeda             !FromBytes,
2125c3739801SMiguel Ojeda             !Unaligned
2126c3739801SMiguel Ojeda         );
2127c3739801SMiguel Ojeda         assert_impls!(
2128c3739801SMiguel Ojeda             NonZeroU32: KnownLayout,
2129c3739801SMiguel Ojeda             Immutable,
2130c3739801SMiguel Ojeda             TryFromBytes,
2131c3739801SMiguel Ojeda             IntoBytes,
2132c3739801SMiguel Ojeda             !FromBytes,
2133c3739801SMiguel Ojeda             !Unaligned
2134c3739801SMiguel Ojeda         );
2135c3739801SMiguel Ojeda         assert_impls!(
2136c3739801SMiguel Ojeda             NonZeroI32: KnownLayout,
2137c3739801SMiguel Ojeda             Immutable,
2138c3739801SMiguel Ojeda             TryFromBytes,
2139c3739801SMiguel Ojeda             IntoBytes,
2140c3739801SMiguel Ojeda             !FromBytes,
2141c3739801SMiguel Ojeda             !Unaligned
2142c3739801SMiguel Ojeda         );
2143c3739801SMiguel Ojeda         assert_impls!(
2144c3739801SMiguel Ojeda             NonZeroU64: KnownLayout,
2145c3739801SMiguel Ojeda             Immutable,
2146c3739801SMiguel Ojeda             TryFromBytes,
2147c3739801SMiguel Ojeda             IntoBytes,
2148c3739801SMiguel Ojeda             !FromBytes,
2149c3739801SMiguel Ojeda             !Unaligned
2150c3739801SMiguel Ojeda         );
2151c3739801SMiguel Ojeda         assert_impls!(
2152c3739801SMiguel Ojeda             NonZeroI64: KnownLayout,
2153c3739801SMiguel Ojeda             Immutable,
2154c3739801SMiguel Ojeda             TryFromBytes,
2155c3739801SMiguel Ojeda             IntoBytes,
2156c3739801SMiguel Ojeda             !FromBytes,
2157c3739801SMiguel Ojeda             !Unaligned
2158c3739801SMiguel Ojeda         );
2159c3739801SMiguel Ojeda         assert_impls!(
2160c3739801SMiguel Ojeda             NonZeroU128: KnownLayout,
2161c3739801SMiguel Ojeda             Immutable,
2162c3739801SMiguel Ojeda             TryFromBytes,
2163c3739801SMiguel Ojeda             IntoBytes,
2164c3739801SMiguel Ojeda             !FromBytes,
2165c3739801SMiguel Ojeda             !Unaligned
2166c3739801SMiguel Ojeda         );
2167c3739801SMiguel Ojeda         assert_impls!(
2168c3739801SMiguel Ojeda             NonZeroI128: KnownLayout,
2169c3739801SMiguel Ojeda             Immutable,
2170c3739801SMiguel Ojeda             TryFromBytes,
2171c3739801SMiguel Ojeda             IntoBytes,
2172c3739801SMiguel Ojeda             !FromBytes,
2173c3739801SMiguel Ojeda             !Unaligned
2174c3739801SMiguel Ojeda         );
2175c3739801SMiguel Ojeda         assert_impls!(
2176c3739801SMiguel Ojeda             NonZeroUsize: KnownLayout,
2177c3739801SMiguel Ojeda             Immutable,
2178c3739801SMiguel Ojeda             TryFromBytes,
2179c3739801SMiguel Ojeda             IntoBytes,
2180c3739801SMiguel Ojeda             !FromBytes,
2181c3739801SMiguel Ojeda             !Unaligned
2182c3739801SMiguel Ojeda         );
2183c3739801SMiguel Ojeda         assert_impls!(
2184c3739801SMiguel Ojeda             NonZeroIsize: KnownLayout,
2185c3739801SMiguel Ojeda             Immutable,
2186c3739801SMiguel Ojeda             TryFromBytes,
2187c3739801SMiguel Ojeda             IntoBytes,
2188c3739801SMiguel Ojeda             !FromBytes,
2189c3739801SMiguel Ojeda             !Unaligned
2190c3739801SMiguel Ojeda         );
2191c3739801SMiguel Ojeda 
2192c3739801SMiguel Ojeda         assert_impls!(Option<NonZeroU8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
2193c3739801SMiguel Ojeda         assert_impls!(Option<NonZeroI8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
2194c3739801SMiguel Ojeda         assert_impls!(Option<NonZeroU16>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
2195c3739801SMiguel Ojeda         assert_impls!(Option<NonZeroI16>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
2196c3739801SMiguel Ojeda         assert_impls!(Option<NonZeroU32>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
2197c3739801SMiguel Ojeda         assert_impls!(Option<NonZeroI32>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
2198c3739801SMiguel Ojeda         assert_impls!(Option<NonZeroU64>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
2199c3739801SMiguel Ojeda         assert_impls!(Option<NonZeroI64>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
2200c3739801SMiguel Ojeda         assert_impls!(Option<NonZeroU128>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
2201c3739801SMiguel Ojeda         assert_impls!(Option<NonZeroI128>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
2202c3739801SMiguel Ojeda         assert_impls!(Option<NonZeroUsize>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
2203c3739801SMiguel Ojeda         assert_impls!(Option<NonZeroIsize>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
2204c3739801SMiguel Ojeda 
2205c3739801SMiguel Ojeda         // Implements none of the ZC traits.
2206c3739801SMiguel Ojeda         struct NotZerocopy;
2207c3739801SMiguel Ojeda 
2208c3739801SMiguel Ojeda         #[rustfmt::skip]
2209c3739801SMiguel Ojeda         type FnManyArgs = fn(
2210c3739801SMiguel Ojeda             NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
2211c3739801SMiguel Ojeda         ) -> (NotZerocopy, NotZerocopy);
2212c3739801SMiguel Ojeda 
2213c3739801SMiguel Ojeda         // Allowed, because we're not actually using this type for FFI.
2214c3739801SMiguel Ojeda         #[allow(improper_ctypes_definitions)]
2215c3739801SMiguel Ojeda         #[rustfmt::skip]
2216c3739801SMiguel Ojeda         type ECFnManyArgs = extern "C" fn(
2217c3739801SMiguel Ojeda             NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
2218c3739801SMiguel Ojeda         ) -> (NotZerocopy, NotZerocopy);
2219c3739801SMiguel Ojeda 
2220c3739801SMiguel Ojeda         #[cfg(feature = "alloc")]
2221c3739801SMiguel Ojeda         assert_impls!(Option<Box<UnsafeCell<NotZerocopy>>>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2222c3739801SMiguel Ojeda         assert_impls!(Option<Box<[UnsafeCell<NotZerocopy>]>>: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2223c3739801SMiguel Ojeda         assert_impls!(Option<&'static UnsafeCell<NotZerocopy>>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2224c3739801SMiguel Ojeda         assert_impls!(Option<&'static [UnsafeCell<NotZerocopy>]>: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2225c3739801SMiguel Ojeda         assert_impls!(Option<&'static mut UnsafeCell<NotZerocopy>>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2226c3739801SMiguel Ojeda         assert_impls!(Option<&'static mut [UnsafeCell<NotZerocopy>]>: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2227c3739801SMiguel Ojeda         assert_impls!(Option<NonNull<UnsafeCell<NotZerocopy>>>: KnownLayout, TryFromBytes, FromZeros, Immutable, !FromBytes, !IntoBytes, !Unaligned);
2228c3739801SMiguel Ojeda         assert_impls!(Option<NonNull<[UnsafeCell<NotZerocopy>]>>: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2229c3739801SMiguel Ojeda         assert_impls!(Option<fn()>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2230c3739801SMiguel Ojeda         assert_impls!(Option<FnManyArgs>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2231c3739801SMiguel Ojeda         assert_impls!(Option<extern "C" fn()>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2232c3739801SMiguel Ojeda         assert_impls!(Option<ECFnManyArgs>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2233c3739801SMiguel Ojeda 
2234c3739801SMiguel Ojeda         assert_impls!(PhantomData<NotZerocopy>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
2235c3739801SMiguel Ojeda         assert_impls!(PhantomData<UnsafeCell<()>>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
2236c3739801SMiguel Ojeda         assert_impls!(PhantomData<[u8]>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
2237c3739801SMiguel Ojeda 
2238c3739801SMiguel Ojeda         assert_impls!(ManuallyDrop<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
2239c3739801SMiguel Ojeda         // This test is important because it allows us to test our hand-rolled
2240c3739801SMiguel Ojeda         // implementation of `<ManuallyDrop<T> as TryFromBytes>::is_bit_valid`.
2241c3739801SMiguel Ojeda         assert_impls!(ManuallyDrop<bool>: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes);
2242c3739801SMiguel Ojeda         assert_impls!(ManuallyDrop<[u8]>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
2243c3739801SMiguel Ojeda         // This test is important because it allows us to test our hand-rolled
2244c3739801SMiguel Ojeda         // implementation of `<ManuallyDrop<T> as TryFromBytes>::is_bit_valid`.
2245c3739801SMiguel Ojeda         assert_impls!(ManuallyDrop<[bool]>: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes);
2246c3739801SMiguel Ojeda         assert_impls!(ManuallyDrop<NotZerocopy>: !Immutable, !TryFromBytes, !KnownLayout, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2247c3739801SMiguel Ojeda         assert_impls!(ManuallyDrop<[NotZerocopy]>: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2248c3739801SMiguel Ojeda         assert_impls!(ManuallyDrop<UnsafeCell<()>>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable);
2249c3739801SMiguel Ojeda         assert_impls!(ManuallyDrop<[UnsafeCell<u8>]>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable);
2250c3739801SMiguel Ojeda         assert_impls!(ManuallyDrop<[UnsafeCell<bool>]>: KnownLayout, TryFromBytes, FromZeros, IntoBytes, Unaligned, !Immutable, !FromBytes);
2251c3739801SMiguel Ojeda 
2252c3739801SMiguel Ojeda         assert_impls!(CoreMaybeUninit<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, Unaligned, !IntoBytes);
2253c3739801SMiguel Ojeda         assert_impls!(CoreMaybeUninit<NotZerocopy>: KnownLayout, TryFromBytes, FromZeros, FromBytes, !Immutable, !IntoBytes, !Unaligned);
2254c3739801SMiguel Ojeda         assert_impls!(CoreMaybeUninit<UnsafeCell<()>>: KnownLayout, TryFromBytes, FromZeros, FromBytes, Unaligned, !Immutable, !IntoBytes);
2255c3739801SMiguel Ojeda 
2256c3739801SMiguel Ojeda         assert_impls!(Wrapping<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
2257c3739801SMiguel Ojeda         // This test is important because it allows us to test our hand-rolled
2258c3739801SMiguel Ojeda         // implementation of `<Wrapping<T> as TryFromBytes>::is_bit_valid`.
2259c3739801SMiguel Ojeda         assert_impls!(Wrapping<bool>: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes);
2260c3739801SMiguel Ojeda         assert_impls!(Wrapping<NotZerocopy>: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2261c3739801SMiguel Ojeda         assert_impls!(Wrapping<UnsafeCell<()>>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable);
2262c3739801SMiguel Ojeda 
2263c3739801SMiguel Ojeda         assert_impls!(Unalign<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
2264c3739801SMiguel Ojeda         // This test is important because it allows us to test our hand-rolled
2265c3739801SMiguel Ojeda         // implementation of `<Unalign<T> as TryFromBytes>::is_bit_valid`.
2266c3739801SMiguel Ojeda         assert_impls!(Unalign<bool>: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes);
2267c3739801SMiguel Ojeda         assert_impls!(Unalign<NotZerocopy>: KnownLayout, Unaligned, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes);
2268c3739801SMiguel Ojeda 
2269c3739801SMiguel Ojeda         assert_impls!(
2270c3739801SMiguel Ojeda             [u8]: KnownLayout,
2271c3739801SMiguel Ojeda             Immutable,
2272c3739801SMiguel Ojeda             TryFromBytes,
2273c3739801SMiguel Ojeda             FromZeros,
2274c3739801SMiguel Ojeda             FromBytes,
2275c3739801SMiguel Ojeda             IntoBytes,
2276c3739801SMiguel Ojeda             Unaligned
2277c3739801SMiguel Ojeda         );
2278c3739801SMiguel Ojeda         assert_impls!(
2279c3739801SMiguel Ojeda             [bool]: KnownLayout,
2280c3739801SMiguel Ojeda             Immutable,
2281c3739801SMiguel Ojeda             TryFromBytes,
2282c3739801SMiguel Ojeda             FromZeros,
2283c3739801SMiguel Ojeda             IntoBytes,
2284c3739801SMiguel Ojeda             Unaligned,
2285c3739801SMiguel Ojeda             !FromBytes
2286c3739801SMiguel Ojeda         );
2287c3739801SMiguel Ojeda         assert_impls!([NotZerocopy]: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2288c3739801SMiguel Ojeda         assert_impls!(
2289c3739801SMiguel Ojeda             [u8; 0]: KnownLayout,
2290c3739801SMiguel Ojeda             Immutable,
2291c3739801SMiguel Ojeda             TryFromBytes,
2292c3739801SMiguel Ojeda             FromZeros,
2293c3739801SMiguel Ojeda             FromBytes,
2294c3739801SMiguel Ojeda             IntoBytes,
2295c3739801SMiguel Ojeda             Unaligned,
2296c3739801SMiguel Ojeda         );
2297c3739801SMiguel Ojeda         assert_impls!(
2298c3739801SMiguel Ojeda             [NotZerocopy; 0]: KnownLayout,
2299c3739801SMiguel Ojeda             !Immutable,
2300c3739801SMiguel Ojeda             !TryFromBytes,
2301c3739801SMiguel Ojeda             !FromZeros,
2302c3739801SMiguel Ojeda             !FromBytes,
2303c3739801SMiguel Ojeda             !IntoBytes,
2304c3739801SMiguel Ojeda             !Unaligned
2305c3739801SMiguel Ojeda         );
2306c3739801SMiguel Ojeda         assert_impls!(
2307c3739801SMiguel Ojeda             [u8; 1]: KnownLayout,
2308c3739801SMiguel Ojeda             Immutable,
2309c3739801SMiguel Ojeda             TryFromBytes,
2310c3739801SMiguel Ojeda             FromZeros,
2311c3739801SMiguel Ojeda             FromBytes,
2312c3739801SMiguel Ojeda             IntoBytes,
2313c3739801SMiguel Ojeda             Unaligned,
2314c3739801SMiguel Ojeda         );
2315c3739801SMiguel Ojeda         assert_impls!(
2316c3739801SMiguel Ojeda             [NotZerocopy; 1]: KnownLayout,
2317c3739801SMiguel Ojeda             !Immutable,
2318c3739801SMiguel Ojeda             !TryFromBytes,
2319c3739801SMiguel Ojeda             !FromZeros,
2320c3739801SMiguel Ojeda             !FromBytes,
2321c3739801SMiguel Ojeda             !IntoBytes,
2322c3739801SMiguel Ojeda             !Unaligned
2323c3739801SMiguel Ojeda         );
2324c3739801SMiguel Ojeda 
2325c3739801SMiguel Ojeda         assert_impls!(*const NotZerocopy: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2326c3739801SMiguel Ojeda         assert_impls!(*mut NotZerocopy: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2327c3739801SMiguel Ojeda         assert_impls!(*const [NotZerocopy]: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2328c3739801SMiguel Ojeda         assert_impls!(*mut [NotZerocopy]: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2329c3739801SMiguel Ojeda         assert_impls!(*const dyn Debug: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2330c3739801SMiguel Ojeda         assert_impls!(*mut dyn Debug: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
2331c3739801SMiguel Ojeda 
2332c3739801SMiguel Ojeda         #[cfg(feature = "simd")]
2333c3739801SMiguel Ojeda         {
2334c3739801SMiguel Ojeda             #[allow(unused_macros)]
2335c3739801SMiguel Ojeda             macro_rules! test_simd_arch_mod {
2336c3739801SMiguel Ojeda                 ($arch:ident, $($typ:ident),*) => {
2337c3739801SMiguel Ojeda                     {
2338c3739801SMiguel Ojeda                         use core::arch::$arch::{$($typ),*};
2339c3739801SMiguel Ojeda                         use crate::*;
2340c3739801SMiguel Ojeda                         $( assert_impls!($typ: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); )*
2341c3739801SMiguel Ojeda                     }
2342c3739801SMiguel Ojeda                 };
2343c3739801SMiguel Ojeda             }
2344c3739801SMiguel Ojeda             #[cfg(target_arch = "x86")]
2345c3739801SMiguel Ojeda             test_simd_arch_mod!(x86, __m128, __m128d, __m128i, __m256, __m256d, __m256i);
2346c3739801SMiguel Ojeda 
2347c3739801SMiguel Ojeda             #[cfg(all(not(no_zerocopy_simd_x86_avx12_1_89_0), target_arch = "x86"))]
2348c3739801SMiguel Ojeda             test_simd_arch_mod!(x86, __m512bh, __m512, __m512d, __m512i);
2349c3739801SMiguel Ojeda 
2350c3739801SMiguel Ojeda             #[cfg(target_arch = "x86_64")]
2351c3739801SMiguel Ojeda             test_simd_arch_mod!(x86_64, __m128, __m128d, __m128i, __m256, __m256d, __m256i);
2352c3739801SMiguel Ojeda 
2353c3739801SMiguel Ojeda             #[cfg(all(not(no_zerocopy_simd_x86_avx12_1_89_0), target_arch = "x86_64"))]
2354c3739801SMiguel Ojeda             test_simd_arch_mod!(x86_64, __m512bh, __m512, __m512d, __m512i);
2355c3739801SMiguel Ojeda 
2356c3739801SMiguel Ojeda             #[cfg(target_arch = "wasm32")]
2357c3739801SMiguel Ojeda             test_simd_arch_mod!(wasm32, v128);
2358c3739801SMiguel Ojeda 
2359c3739801SMiguel Ojeda             #[cfg(all(feature = "simd-nightly", target_arch = "powerpc"))]
2360c3739801SMiguel Ojeda             test_simd_arch_mod!(
2361c3739801SMiguel Ojeda                 powerpc,
2362c3739801SMiguel Ojeda                 vector_bool_long,
2363c3739801SMiguel Ojeda                 vector_double,
2364c3739801SMiguel Ojeda                 vector_signed_long,
2365c3739801SMiguel Ojeda                 vector_unsigned_long
2366c3739801SMiguel Ojeda             );
2367c3739801SMiguel Ojeda 
2368c3739801SMiguel Ojeda             #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))]
2369c3739801SMiguel Ojeda             test_simd_arch_mod!(
2370c3739801SMiguel Ojeda                 powerpc64,
2371c3739801SMiguel Ojeda                 vector_bool_long,
2372c3739801SMiguel Ojeda                 vector_double,
2373c3739801SMiguel Ojeda                 vector_signed_long,
2374c3739801SMiguel Ojeda                 vector_unsigned_long
2375c3739801SMiguel Ojeda             );
2376c3739801SMiguel Ojeda             #[cfg(all(target_arch = "aarch64", not(no_zerocopy_aarch64_simd_1_59_0)))]
2377c3739801SMiguel Ojeda             #[rustfmt::skip]
2378c3739801SMiguel Ojeda             test_simd_arch_mod!(
2379c3739801SMiguel Ojeda                 aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t,
2380c3739801SMiguel Ojeda                 int8x8x3_t, int8x8x4_t, int8x16_t, int8x16x2_t, int8x16x3_t, int8x16x4_t, int16x4_t,
2381c3739801SMiguel Ojeda                 int16x8_t, int32x2_t, int32x4_t, int64x1_t, int64x2_t, poly8x8_t, poly8x8x2_t, poly8x8x3_t,
2382c3739801SMiguel Ojeda                 poly8x8x4_t, poly8x16_t, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t, poly16x4_t, poly16x8_t,
2383c3739801SMiguel Ojeda                 poly64x1_t, poly64x2_t, uint8x8_t, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t, uint8x16_t,
2384c3739801SMiguel Ojeda                 uint8x16x2_t, uint8x16x3_t, uint8x16x4_t, uint16x4_t, uint16x4x2_t, uint16x4x3_t,
2385c3739801SMiguel Ojeda                 uint16x4x4_t, uint16x8_t, uint32x2_t, uint32x4_t, uint64x1_t, uint64x2_t
2386c3739801SMiguel Ojeda             );
2387c3739801SMiguel Ojeda         }
2388c3739801SMiguel Ojeda     }
2389c3739801SMiguel Ojeda }
2390