zerocopy/impls.rs
1// Copyright 2024 The Fuchsia Authors
2//
3// Licensed under the 2-Clause BSD License <LICENSE-BSD or
4// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
5// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
6// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
7// This file may not be copied, modified, or distributed except according to
8// those terms.
9
10use super::*;
11
12safety_comment! {
13 /// SAFETY:
14 /// Per the reference [1], "the unit tuple (`()`) ... is guaranteed as a
15 /// zero-sized type to have a size of 0 and an alignment of 1."
16 /// - `Immutable`: `()` self-evidently does not contain any `UnsafeCell`s.
17 /// - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: There is
18 /// only one possible sequence of 0 bytes, and `()` is inhabited.
19 /// - `IntoBytes`: Since `()` has size 0, it contains no padding bytes.
20 /// - `Unaligned`: `()` has alignment 1.
21 ///
22 /// [1] https://doc.rust-lang.org/reference/type-layout.html#tuple-layout
23 unsafe_impl!((): Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
24 assert_unaligned!(());
25}
26
27safety_comment! {
28 /// SAFETY:
29 /// - `Immutable`: These types self-evidently do not contain any
30 /// `UnsafeCell`s.
31 /// - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: all bit
32 /// patterns are valid for numeric types [1]
33 /// - `IntoBytes`: numeric types have no padding bytes [1]
34 /// - `Unaligned` (`u8` and `i8` only): The reference [2] specifies the size
35 /// of `u8` and `i8` as 1 byte. We also know that:
36 /// - Alignment is >= 1 [3]
37 /// - Size is an integer multiple of alignment [4]
38 /// - The only value >= 1 for which 1 is an integer multiple is 1
39 /// Therefore, the only possible alignment for `u8` and `i8` is 1.
40 ///
41 /// [1] Per https://doc.rust-lang.org/beta/reference/types/numeric.html#bit-validity:
42 ///
43 /// For every numeric type, `T`, the bit validity of `T` is equivalent to
44 /// the bit validity of `[u8; size_of::<T>()]`. An uninitialized byte is
45 /// not a valid `u8`.
46 ///
47 /// TODO(https://github.com/rust-lang/reference/pull/1392): Once this text
48 /// is available on the Stable docs, cite those instead.
49 ///
50 /// [2] https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout
51 ///
52 /// [3] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
53 ///
54 /// Alignment is measured in bytes, and must be at least 1.
55 ///
56 /// [4] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
57 ///
58 /// The size of a value is always a multiple of its alignment.
59 ///
60 /// TODO(#278): Once we've updated the trait docs to refer to `u8`s rather
61 /// than bits or bytes, update this comment, especially the reference to
62 /// [1].
63 unsafe_impl!(u8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
64 unsafe_impl!(i8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
65 assert_unaligned!(u8, i8);
66 unsafe_impl!(u16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
67 unsafe_impl!(i16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
68 unsafe_impl!(u32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
69 unsafe_impl!(i32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
70 unsafe_impl!(u64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
71 unsafe_impl!(i64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
72 unsafe_impl!(u128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
73 unsafe_impl!(i128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
74 unsafe_impl!(usize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
75 unsafe_impl!(isize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
76 unsafe_impl!(f32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
77 unsafe_impl!(f64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
78}
79
80safety_comment! {
81 /// SAFETY:
82 /// - `Immutable`: `bool` self-evidently does not contain any `UnsafeCell`s.
83 /// - `FromZeros`: Valid since "[t]he value false has the bit pattern 0x00"
84 /// [1].
85 /// - `IntoBytes`: Since "the boolean type has a size and alignment of 1
86 /// each" and "The value false has the bit pattern 0x00 and the value true
87 /// has the bit pattern 0x01" [1]. Thus, the only byte of the bool is
88 /// always initialized.
89 /// - `Unaligned`: Per the reference [1], "[a]n object with the boolean type
90 /// has a size and alignment of 1 each."
91 ///
92 /// [1] https://doc.rust-lang.org/reference/types/boolean.html
93 unsafe_impl!(bool: Immutable, FromZeros, IntoBytes, Unaligned);
94 assert_unaligned!(bool);
95 /// SAFETY:
96 /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
97 /// closure:
98 /// - Given `t: *mut bool` and `let r = *mut u8`, `r` refers to an object
99 /// of the same size as that referred to by `t`. This is true because
100 /// `bool` and `u8` have the same size (1 byte) [1]. Neither `r` nor `t`
101 /// contain `UnsafeCell`s because neither `bool` nor `u8` do [4].
102 /// - Since the closure takes a `&u8` argument, given a `Maybe<'a,
103 /// bool>` which satisfies the preconditions of
104 /// `TryFromBytes::<bool>::is_bit_valid`, it must be guaranteed that the
105 /// memory referenced by that `MaybeValid` always contains a valid `u8`.
106 /// Since `bool`'s single byte is always initialized, `is_bit_valid`'s
107 /// precondition requires that the same is true of its argument. Since
108 /// `u8`'s only bit validity invariant is that its single byte must be
109 /// initialized, this memory is guaranteed to contain a valid `u8`.
110 /// - The impl must only return `true` for its argument if the original
111 /// `Maybe<bool>` refers to a valid `bool`. We only return true if
112 /// the `u8` value is 0 or 1, and both of these are valid values for
113 /// `bool`. [3]
114 ///
115 /// [1] Per https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout:
116 ///
117 /// The size of most primitives is given in this table.
118 ///
119 /// | Type | `size_of::<Type>() ` |
120 /// |-----------|----------------------|
121 /// | `bool` | 1 |
122 /// | `u8`/`i8` | 1 |
123 ///
124 /// [2] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
125 ///
126 /// The size of a value is always a multiple of its alignment.
127 ///
128 /// [3] Per https://doc.rust-lang.org/reference/types/boolean.html:
129 ///
130 /// The value false has the bit pattern 0x00 and the value true has the
131 /// bit pattern 0x01.
132 ///
133 /// [4] TODO(#429): Justify this claim.
134 unsafe_impl!(bool: TryFromBytes; |byte: MaybeAligned<u8>| *byte.unaligned_as_ref() < 2);
135}
136safety_comment! {
137 /// SAFETY:
138 /// - `Immutable`: `char` self-evidently does not contain any `UnsafeCell`s.
139 /// - `FromZeros`: Per reference [1], "[a] value of type char is a Unicode
140 /// scalar value (i.e. a code point that is not a surrogate), represented
141 /// as a 32-bit unsigned word in the 0x0000 to 0xD7FF or 0xE000 to
142 /// 0x10FFFF range" which contains 0x0000.
143 /// - `IntoBytes`: `char` is per reference [1] "represented as a 32-bit
144 /// unsigned word" (`u32`) which is `IntoBytes`. Note that unlike `u32`,
145 /// not all bit patterns are valid for `char`.
146 ///
147 /// [1] https://doc.rust-lang.org/reference/types/textual.html
148 unsafe_impl!(char: Immutable, FromZeros, IntoBytes);
149 /// SAFETY:
150 /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
151 /// closure:
152 /// - Given `t: *mut char` and `let r = *mut u32`, `r` refers to an object
153 /// of the same size as that referred to by `t`. This is true because
154 /// `char` and `u32` have the same size [1]. Neither `r` nor `t` contain
155 /// `UnsafeCell`s because neither `char` nor `u32` do [4].
156 /// - Since the closure takes a `&u32` argument, given a `Maybe<'a,
157 /// char>` which satisfies the preconditions of
158 /// `TryFromBytes::<char>::is_bit_valid`, it must be guaranteed that the
159 /// memory referenced by that `MaybeValid` always contains a valid
160 /// `u32`. Since `char`'s bytes are always initialized [2],
161 /// `is_bit_valid`'s precondition requires that the same is true of its
162 /// argument. Since `u32`'s only bit validity invariant is that its
163 /// bytes must be initialized, this memory is guaranteed to contain a
164 /// valid `u32`.
165 /// - The impl must only return `true` for its argument if the original
166 /// `Maybe<char>` refers to a valid `char`. `char::from_u32`
167 /// guarantees that it returns `None` if its input is not a valid
168 /// `char`. [3]
169 ///
170 /// [1] Per https://doc.rust-lang.org/nightly/reference/types/textual.html#layout-and-bit-validity:
171 ///
172 /// `char` is guaranteed to have the same size and alignment as `u32` on
173 /// all platforms.
174 ///
175 /// [2] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32:
176 ///
177 /// Every byte of a `char` is guaranteed to be initialized.
178 ///
179 /// [3] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32:
180 ///
181 /// `from_u32()` will return `None` if the input is not a valid value for
182 /// a `char`.
183 ///
184 /// [4] TODO(#429): Justify this claim.
185 unsafe_impl!(char: TryFromBytes; |candidate: MaybeAligned<u32>| {
186 let candidate = candidate.read_unaligned();
187 char::from_u32(candidate).is_some()
188 });
189}
190safety_comment! {
191 /// SAFETY:
192 /// Per the Reference [1], `str` has the same layout as `[u8]`.
193 /// - `Immutable`: `[u8]` does not contain any `UnsafeCell`s.
194 /// - `FromZeros`, `IntoBytes`, `Unaligned`: `[u8]` is `FromZeros`,
195 /// `IntoBytes`, and `Unaligned`.
196 ///
197 /// Note that we don't `assert_unaligned!(str)` because `assert_unaligned!`
198 /// uses `align_of`, which only works for `Sized` types.
199 ///
200 /// TODO(#429):
201 /// - Add quotes from documentation.
202 /// - Improve safety proof for `FromZeros` and `IntoBytes`; having the same
203 /// layout as `[u8]` isn't sufficient.
204 ///
205 /// [1] https://doc.rust-lang.org/reference/type-layout.html#str-layout
206 unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unaligned);
207 /// SAFETY:
208 /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
209 /// closure:
210 /// - Given `t: *mut str` and `let r = *mut [u8]`, `r` refers to an object
211 /// of the same size as that referred to by `t`. This is true because
212 /// `str` and `[u8]` have the same representation. [1] Neither `t` nor
213 /// `r` contain `UnsafeCell`s because `[u8]` doesn't, and both `t` and
214 /// `r` have that representation.
215 /// - Since the closure takes a `&[u8]` argument, given a `Maybe<'a,
216 /// str>` which satisfies the preconditions of
217 /// `TryFromBytes::<str>::is_bit_valid`, it must be guaranteed that the
218 /// memory referenced by that `MaybeValid` always contains a valid
219 /// `[u8]`. Since `str`'s bytes are always initialized [1],
220 /// `is_bit_valid`'s precondition requires that the same is true of its
221 /// argument. Since `[u8]`'s only bit validity invariant is that its
222 /// bytes must be initialized, this memory is guaranteed to contain a
223 /// valid `[u8]`.
224 /// - The impl must only return `true` for its argument if the original
225 /// `Maybe<str>` refers to a valid `str`. `str::from_utf8`
226 /// guarantees that it returns `Err` if its input is not a valid `str`.
227 /// [2]
228 ///
229 /// [1] Per https://doc.rust-lang.org/reference/types/textual.html:
230 ///
231 /// A value of type `str` is represented the same was as `[u8]`.
232 ///
233 /// [2] Per https://doc.rust-lang.org/core/str/fn.from_utf8.html#errors:
234 ///
235 /// Returns `Err` if the slice is not UTF-8.
236 unsafe_impl!(str: TryFromBytes; |candidate: MaybeAligned<[u8]>| {
237 let candidate = candidate.unaligned_as_ref();
238 core::str::from_utf8(candidate).is_ok()
239 });
240}
241
242safety_comment! {
243 // `NonZeroXxx` is `IntoBytes`, but not `FromZeros` or `FromBytes`.
244 //
245 /// SAFETY:
246 /// - `IntoBytes`: `NonZeroXxx` has the same layout as its associated
247 /// primitive. Since it is the same size, this guarantees it has no
248 /// padding - integers have no padding, and there's no room for padding
249 /// if it can represent all of the same values except 0.
250 /// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that
251 /// `Option<NonZeroU8>` and `Option<NonZeroI8>` both have size 1. [1] [2]
252 /// This is worded in a way that makes it unclear whether it's meant as a
253 /// guarantee, but given the purpose of those types, it's virtually
254 /// unthinkable that that would ever change. `Option` cannot be smaller
255 /// than its contained type, which implies that, and `NonZeroX8` are of
256 /// size 1 or 0. `NonZeroX8` can represent multiple states, so they cannot
257 /// be 0 bytes, which means that they must be 1 byte. The only valid
258 /// alignment for a 1-byte type is 1.
259 ///
260 /// TODO(#429):
261 /// - Add quotes from documentation.
262 /// - Add safety comment for `Immutable`. How can we prove that `NonZeroXxx`
263 /// doesn't contain any `UnsafeCell`s? It's obviously true, but it's not
264 /// clear how we'd prove it short of adding text to the stdlib docs that
265 /// says so explicitly, which likely wouldn't be accepted.
266 ///
267 /// [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html
268 /// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html
269 /// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation
270 /// that layout is the same as primitive layout.
271 unsafe_impl!(NonZeroU8: Immutable, IntoBytes, Unaligned);
272 unsafe_impl!(NonZeroI8: Immutable, IntoBytes, Unaligned);
273 assert_unaligned!(NonZeroU8, NonZeroI8);
274 unsafe_impl!(NonZeroU16: Immutable, IntoBytes);
275 unsafe_impl!(NonZeroI16: Immutable, IntoBytes);
276 unsafe_impl!(NonZeroU32: Immutable, IntoBytes);
277 unsafe_impl!(NonZeroI32: Immutable, IntoBytes);
278 unsafe_impl!(NonZeroU64: Immutable, IntoBytes);
279 unsafe_impl!(NonZeroI64: Immutable, IntoBytes);
280 unsafe_impl!(NonZeroU128: Immutable, IntoBytes);
281 unsafe_impl!(NonZeroI128: Immutable, IntoBytes);
282 unsafe_impl!(NonZeroUsize: Immutable, IntoBytes);
283 unsafe_impl!(NonZeroIsize: Immutable, IntoBytes);
284 /// SAFETY:
285 /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
286 /// closure:
287 /// - Given `t: *mut NonZeroXxx` and `let r = *mut xxx`, `r` refers to an
288 /// object of the same size as that referred to by `t`. This is true
289 /// because `NonZeroXxx` and `xxx` have the same size. [1] Neither `r`
290 /// nor `t` refer to any `UnsafeCell`s because neither `NonZeroXxx` [2]
291 /// nor `xxx` do.
292 /// - Since the closure takes a `&xxx` argument, given a `Maybe<'a,
293 /// NonZeroXxx>` which satisfies the preconditions of
294 /// `TryFromBytes::<NonZeroXxx>::is_bit_valid`, it must be guaranteed
295 /// that the memory referenced by that `MabyeValid` always contains a
296 /// valid `xxx`. Since `NonZeroXxx`'s bytes are always initialized [1],
297 /// `is_bit_valid`'s precondition requires that the same is true of its
298 /// argument. Since `xxx`'s only bit validity invariant is that its
299 /// bytes must be initialized, this memory is guaranteed to contain a
300 /// valid `xxx`.
301 /// - The impl must only return `true` for its argument if the original
302 /// `Maybe<NonZeroXxx>` refers to a valid `NonZeroXxx`. The only
303 /// `xxx` which is not also a valid `NonZeroXxx` is 0. [1]
304 ///
305 /// [1] Per https://doc.rust-lang.org/core/num/struct.NonZeroU16.html:
306 ///
307 /// `NonZeroU16` is guaranteed to have the same layout and bit validity as
308 /// `u16` with the exception that `0` is not a valid instance.
309 ///
310 /// [2] `NonZeroXxx` self-evidently does not contain `UnsafeCell`s. This is
311 /// not a proof, but we are accepting this as a known risk per #1358.
312 unsafe_impl!(NonZeroU8: TryFromBytes; |n: MaybeAligned<u8>| NonZeroU8::new(n.read_unaligned()).is_some());
313 unsafe_impl!(NonZeroI8: TryFromBytes; |n: MaybeAligned<i8>| NonZeroI8::new(n.read_unaligned()).is_some());
314 unsafe_impl!(NonZeroU16: TryFromBytes; |n: MaybeAligned<u16>| NonZeroU16::new(n.read_unaligned()).is_some());
315 unsafe_impl!(NonZeroI16: TryFromBytes; |n: MaybeAligned<i16>| NonZeroI16::new(n.read_unaligned()).is_some());
316 unsafe_impl!(NonZeroU32: TryFromBytes; |n: MaybeAligned<u32>| NonZeroU32::new(n.read_unaligned()).is_some());
317 unsafe_impl!(NonZeroI32: TryFromBytes; |n: MaybeAligned<i32>| NonZeroI32::new(n.read_unaligned()).is_some());
318 unsafe_impl!(NonZeroU64: TryFromBytes; |n: MaybeAligned<u64>| NonZeroU64::new(n.read_unaligned()).is_some());
319 unsafe_impl!(NonZeroI64: TryFromBytes; |n: MaybeAligned<i64>| NonZeroI64::new(n.read_unaligned()).is_some());
320 unsafe_impl!(NonZeroU128: TryFromBytes; |n: MaybeAligned<u128>| NonZeroU128::new(n.read_unaligned()).is_some());
321 unsafe_impl!(NonZeroI128: TryFromBytes; |n: MaybeAligned<i128>| NonZeroI128::new(n.read_unaligned()).is_some());
322 unsafe_impl!(NonZeroUsize: TryFromBytes; |n: MaybeAligned<usize>| NonZeroUsize::new(n.read_unaligned()).is_some());
323 unsafe_impl!(NonZeroIsize: TryFromBytes; |n: MaybeAligned<isize>| NonZeroIsize::new(n.read_unaligned()).is_some());
324}
325safety_comment! {
326 /// SAFETY:
327 /// - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`,
328 /// `IntoBytes`: The Rust compiler reuses `0` value to represent `None`,
329 /// so `size_of::<Option<NonZeroXxx>>() == size_of::<xxx>()`; see
330 /// `NonZeroXxx` documentation.
331 /// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that
332 /// `Option<NonZeroU8>` and `Option<NonZeroI8>` both have size 1. [1] [2]
333 /// This is worded in a way that makes it unclear whether it's meant as a
334 /// guarantee, but given the purpose of those types, it's virtually
335 /// unthinkable that that would ever change. The only valid alignment for
336 /// a 1-byte type is 1.
337 ///
338 /// TODO(#429): Add quotes from documentation.
339 ///
340 /// [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html
341 /// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html
342 ///
343 /// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation
344 /// for layout guarantees.
345 unsafe_impl!(Option<NonZeroU8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
346 unsafe_impl!(Option<NonZeroI8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
347 assert_unaligned!(Option<NonZeroU8>, Option<NonZeroI8>);
348 unsafe_impl!(Option<NonZeroU16>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
349 unsafe_impl!(Option<NonZeroI16>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
350 unsafe_impl!(Option<NonZeroU32>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
351 unsafe_impl!(Option<NonZeroI32>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
352 unsafe_impl!(Option<NonZeroU64>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
353 unsafe_impl!(Option<NonZeroI64>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
354 unsafe_impl!(Option<NonZeroU128>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
355 unsafe_impl!(Option<NonZeroI128>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
356 unsafe_impl!(Option<NonZeroUsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
357 unsafe_impl!(Option<NonZeroIsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
358}
359
360safety_comment! {
361 /// SAFETY:
362 /// While it's not fully documented, the consensus is that `Box<T>` does not
363 /// contain any `UnsafeCell`s for `T: Sized` [1]. This is not a complete
364 /// proof, but we are accepting this as a known risk per #1358.
365 ///
366 /// [1] https://github.com/rust-lang/unsafe-code-guidelines/issues/492
367 #[cfg(feature = "alloc")]
368 unsafe_impl!(
369 #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
370 T: Sized => Immutable for Box<T>
371 );
372}
373
374safety_comment! {
375 /// SAFETY:
376 /// The following types can be transmuted from `[0u8; size_of::<T>()]`. [1]
377 ///
378 /// [1] Per https://doc.rust-lang.org/nightly/core/option/index.html#representation:
379 ///
380 /// Rust guarantees to optimize the following types `T` such that
381 /// [`Option<T>`] has the same size and alignment as `T`. In some of these
382 /// cases, Rust further guarantees that `transmute::<_, Option<T>>([0u8;
383 /// size_of::<T>()])` is sound and produces `Option::<T>::None`. These
384 /// cases are identified by the second column:
385 ///
386 /// | `T` | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? |
387 /// |-----------------------|-----------------------------------------------------------|
388 /// | [`Box<U>`] | when `U: Sized` |
389 /// | `&U` | when `U: Sized` |
390 /// | `&mut U` | when `U: Sized` |
391 /// | [`ptr::NonNull<U>`] | when `U: Sized` |
392 /// | `fn`, `extern "C" fn` | always |
393 ///
394 /// TODO(#429), TODO(https://github.com/rust-lang/rust/pull/115333): Cite
395 /// the Stable docs once they're available.
396 #[cfg(feature = "alloc")]
397 unsafe_impl!(
398 #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
399 T => TryFromBytes for Option<Box<T>>;
400 |c: Maybe<Option<Box<T>>>| pointer::is_zeroed(c)
401 );
402 #[cfg(feature = "alloc")]
403 unsafe_impl!(
404 #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
405 T => FromZeros for Option<Box<T>>
406 );
407 unsafe_impl!(
408 T => TryFromBytes for Option<&'_ T>;
409 |c: Maybe<Option<&'_ T>>| pointer::is_zeroed(c)
410 );
411 unsafe_impl!(T => FromZeros for Option<&'_ T>);
412 unsafe_impl!(
413 T => TryFromBytes for Option<&'_ mut T>;
414 |c: Maybe<Option<&'_ mut T>>| pointer::is_zeroed(c)
415 );
416 unsafe_impl!(T => FromZeros for Option<&'_ mut T>);
417 unsafe_impl!(
418 T => TryFromBytes for Option<NonNull<T>>;
419 |c: Maybe<Option<NonNull<T>>>| pointer::is_zeroed(c)
420 );
421 unsafe_impl!(T => FromZeros for Option<NonNull<T>>);
422 unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_fn!(...));
423 unsafe_impl_for_power_set!(
424 A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_fn!(...);
425 |c: Maybe<Self>| pointer::is_zeroed(c)
426 );
427 unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_extern_c_fn!(...));
428 unsafe_impl_for_power_set!(
429 A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_extern_c_fn!(...);
430 |c: Maybe<Self>| pointer::is_zeroed(c)
431 );
432}
433
434safety_comment! {
435 /// SAFETY:
436 /// `fn()` and `extern "C" fn()` self-evidently do not contain
437 /// `UnsafeCell`s. This is not a proof, but we are accepting this as a known
438 /// risk per #1358.
439 unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_fn!(...));
440 unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_extern_c_fn!(...));
441}
442
443#[cfg(all(
444 zerocopy_target_has_atomics,
445 any(
446 target_has_atomic = "8",
447 target_has_atomic = "16",
448 target_has_atomic = "32",
449 target_has_atomic = "64",
450 target_has_atomic = "ptr"
451 )
452))]
453mod atomics {
454 use super::*;
455
456 macro_rules! impl_traits_for_atomics {
457 ($($atomics:ident),* $(,)?) => {
458 $(
459 impl_known_layout!($atomics);
460 impl_for_transparent_wrapper!(=> TryFromBytes for $atomics);
461 impl_for_transparent_wrapper!(=> FromZeros for $atomics);
462 impl_for_transparent_wrapper!(=> FromBytes for $atomics);
463 impl_for_transparent_wrapper!(=> IntoBytes for $atomics);
464 )*
465 };
466 }
467
468 #[cfg(target_has_atomic = "8")]
469 #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "8")))]
470 mod atomic_8 {
471 use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
472
473 use super::*;
474
475 impl_traits_for_atomics!(AtomicU8, AtomicI8);
476
477 impl_known_layout!(AtomicBool);
478
479 impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool);
480 impl_for_transparent_wrapper!(=> FromZeros for AtomicBool);
481 impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool);
482
483 safety_comment! {
484 /// SAFETY:
485 /// Per [1], `AtomicBool`, `AtomicU8`, and `AtomicI8` have the same
486 /// size as `bool`, `u8`, and `i8` respectively. Since a type's
487 /// alignment cannot be smaller than 1 [2], and since its alignment
488 /// cannot be greater than its size [3], the only possible value for
489 /// the alignment is 1. Thus, it is sound to implement `Unaligned`.
490 ///
491 /// [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU8.html:
492 ///
493 /// This type has the same size, alignment, and bit validity as
494 /// the underlying integer type
495 ///
496 /// [2] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
497 ///
498 /// Alignment is measured in bytes, and must be at least 1.
499 ///
500 /// [3] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
501 ///
502 /// The size of a value is always a multiple of its alignment.
503 unsafe_impl!(AtomicBool: Unaligned);
504 unsafe_impl!(AtomicU8: Unaligned);
505 unsafe_impl!(AtomicI8: Unaligned);
506 assert_unaligned!(AtomicBool, AtomicU8, AtomicI8);
507
508 /// SAFETY:
509 /// All of these pass an atomic type and that type's native equivalent, as
510 /// required by the macro safety preconditions.
511 unsafe_impl_transparent_wrapper_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]);
512 }
513 }
514
515 #[cfg(target_has_atomic = "16")]
516 #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "16")))]
517 mod atomic_16 {
518 use core::sync::atomic::{AtomicI16, AtomicU16};
519
520 use super::*;
521
522 impl_traits_for_atomics!(AtomicU16, AtomicI16);
523
524 safety_comment! {
525 /// SAFETY:
526 /// All of these pass an atomic type and that type's native equivalent, as
527 /// required by the macro safety preconditions.
528 unsafe_impl_transparent_wrapper_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]);
529 }
530 }
531
532 #[cfg(target_has_atomic = "32")]
533 #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "32")))]
534 mod atomic_32 {
535 use core::sync::atomic::{AtomicI32, AtomicU32};
536
537 use super::*;
538
539 impl_traits_for_atomics!(AtomicU32, AtomicI32);
540
541 safety_comment! {
542 /// SAFETY:
543 /// All of these pass an atomic type and that type's native equivalent, as
544 /// required by the macro safety preconditions.
545 unsafe_impl_transparent_wrapper_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]);
546 }
547 }
548
549 #[cfg(target_has_atomic = "64")]
550 #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "64")))]
551 mod atomic_64 {
552 use core::sync::atomic::{AtomicI64, AtomicU64};
553
554 use super::*;
555
556 impl_traits_for_atomics!(AtomicU64, AtomicI64);
557
558 safety_comment! {
559 /// SAFETY:
560 /// All of these pass an atomic type and that type's native equivalent, as
561 /// required by the macro safety preconditions.
562 unsafe_impl_transparent_wrapper_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]);
563 }
564 }
565
566 #[cfg(target_has_atomic = "ptr")]
567 #[cfg_attr(doc_cfg, doc(cfg(target_has_atomic = "ptr")))]
568 mod atomic_ptr {
569 use core::sync::atomic::{AtomicIsize, AtomicPtr, AtomicUsize};
570
571 use super::*;
572
573 impl_traits_for_atomics!(AtomicUsize, AtomicIsize);
574
575 impl_known_layout!(T => AtomicPtr<T>);
576
577 // TODO(#170): Implement `FromBytes` and `IntoBytes` once we implement
578 // those traits for `*mut T`.
579 impl_for_transparent_wrapper!(T => TryFromBytes for AtomicPtr<T>);
580 impl_for_transparent_wrapper!(T => FromZeros for AtomicPtr<T>);
581
582 safety_comment! {
583 /// SAFETY:
584 /// This passes an atomic type and that type's native equivalent, as
585 /// required by the macro safety preconditions.
586 unsafe_impl_transparent_wrapper_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]);
587 unsafe_impl_transparent_wrapper_for_atomic!(T => AtomicPtr<T> [*mut T]);
588 }
589 }
590}
591
592safety_comment! {
593 /// SAFETY:
594 /// Per reference [1]:
595 /// "For all T, the following are guaranteed:
596 /// size_of::<PhantomData<T>>() == 0
597 /// align_of::<PhantomData<T>>() == 1".
598 /// This gives:
599 /// - `Immutable`: `PhantomData` has no fields.
600 /// - `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`: There is
601 /// only one possible sequence of 0 bytes, and `PhantomData` is inhabited.
602 /// - `IntoBytes`: Since `PhantomData` has size 0, it contains no padding
603 /// bytes.
604 /// - `Unaligned`: Per the preceding reference, `PhantomData` has alignment
605 /// 1.
606 ///
607 /// [1] https://doc.rust-lang.org/std/marker/struct.PhantomData.html#layout-1
608 unsafe_impl!(T: ?Sized => Immutable for PhantomData<T>);
609 unsafe_impl!(T: ?Sized => TryFromBytes for PhantomData<T>);
610 unsafe_impl!(T: ?Sized => FromZeros for PhantomData<T>);
611 unsafe_impl!(T: ?Sized => FromBytes for PhantomData<T>);
612 unsafe_impl!(T: ?Sized => IntoBytes for PhantomData<T>);
613 unsafe_impl!(T: ?Sized => Unaligned for PhantomData<T>);
614 assert_unaligned!(PhantomData<()>, PhantomData<u8>, PhantomData<u64>);
615}
616
617impl_for_transparent_wrapper!(T: Immutable => Immutable for Wrapping<T>);
618impl_for_transparent_wrapper!(T: TryFromBytes => TryFromBytes for Wrapping<T>);
619impl_for_transparent_wrapper!(T: FromZeros => FromZeros for Wrapping<T>);
620impl_for_transparent_wrapper!(T: FromBytes => FromBytes for Wrapping<T>);
621impl_for_transparent_wrapper!(T: IntoBytes => IntoBytes for Wrapping<T>);
622impl_for_transparent_wrapper!(T: Unaligned => Unaligned for Wrapping<T>);
623assert_unaligned!(Wrapping<()>, Wrapping<u8>);
624
625safety_comment! {
626 /// SAFETY:
627 /// `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`:
628 /// `MaybeUninit<T>` has no restrictions on its contents.
629 unsafe_impl!(T => TryFromBytes for MaybeUninit<T>);
630 unsafe_impl!(T => FromZeros for MaybeUninit<T>);
631 unsafe_impl!(T => FromBytes for MaybeUninit<T>);
632}
633
634impl_for_transparent_wrapper!(T: Immutable => Immutable for MaybeUninit<T>);
635impl_for_transparent_wrapper!(T: Unaligned => Unaligned for MaybeUninit<T>);
636assert_unaligned!(MaybeUninit<()>, MaybeUninit<u8>);
637
638impl_for_transparent_wrapper!(T: ?Sized + Immutable => Immutable for ManuallyDrop<T>);
639impl_for_transparent_wrapper!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop<T>);
640impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop<T>);
641impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>);
642impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop<T>);
643impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop<T>);
644assert_unaligned!(ManuallyDrop<()>, ManuallyDrop<u8>);
645
646impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for UnsafeCell<T>);
647impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for UnsafeCell<T>);
648impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell<T>);
649impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for UnsafeCell<T>);
650assert_unaligned!(UnsafeCell<()>, UnsafeCell<u8>);
651
652// SAFETY: See safety comment in `is_bit_valid` impl.
653unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
654 #[allow(clippy::missing_inline_in_public_items)]
655 fn only_derive_is_allowed_to_implement_this_trait()
656 where
657 Self: Sized,
658 {
659 }
660
661 #[inline]
662 fn is_bit_valid<A: invariant::Aliasing + invariant::AtLeast<invariant::Shared>>(
663 candidate: Maybe<'_, Self, A>,
664 ) -> bool {
665 // The only way to implement this function is using an exclusive-aliased
666 // pointer. `UnsafeCell`s cannot be read via shared-aliased pointers
667 // (other than by using `unsafe` code, which we can't use since we can't
668 // guarantee how our users are accessing or modifying the `UnsafeCell`).
669 //
670 // `is_bit_valid` is documented as panicking or failing to monomorphize
671 // if called with a shared-aliased pointer on a type containing an
672 // `UnsafeCell`. In practice, it will always be a monorphization error.
673 // Since `is_bit_valid` is `#[doc(hidden)]` and only called directly
674 // from this crate, we only need to worry about our own code incorrectly
675 // calling `UnsafeCell::is_bit_valid`. The post-monomorphization error
676 // makes it easier to test that this is truly the case, and also means
677 // that if we make a mistake, it will cause downstream code to fail to
678 // compile, which will immediately surface the mistake and give us a
679 // chance to fix it quickly.
680 let c = candidate.into_exclusive_or_post_monomorphization_error();
681
682 // SAFETY: Since `UnsafeCell<T>` and `T` have the same layout and bit
683 // validity, `UnsafeCell<T>` is bit-valid exactly when its wrapped `T`
684 // is. Thus, this is a sound implementation of
685 // `UnsafeCell::is_bit_valid`.
686 T::is_bit_valid(c.get_mut())
687 }
688}
689
690safety_comment! {
691 /// SAFETY:
692 /// Per the reference [1]:
693 ///
694 /// An array of `[T; N]` has a size of `size_of::<T>() * N` and the same
695 /// alignment of `T`. Arrays are laid out so that the zero-based `nth`
696 /// element of the array is offset from the start of the array by `n *
697 /// size_of::<T>()` bytes.
698 ///
699 /// ...
700 ///
701 /// Slices have the same layout as the section of the array they slice.
702 ///
703 /// In other words, the layout of a `[T]` or `[T; N]` is a sequence of `T`s
704 /// laid out back-to-back with no bytes in between. Therefore, `[T]` or `[T;
705 /// N]` are `Immutable`, `TryFromBytes`, `FromZeros`, `FromBytes`, and
706 /// `IntoBytes` if `T` is (respectively). Furthermore, since an array/slice
707 /// has "the same alignment of `T`", `[T]` and `[T; N]` are `Unaligned` if
708 /// `T` is.
709 ///
710 /// Note that we don't `assert_unaligned!` for slice types because
711 /// `assert_unaligned!` uses `align_of`, which only works for `Sized` types.
712 ///
713 /// [1] https://doc.rust-lang.org/reference/type-layout.html#array-layout
714 unsafe_impl!(const N: usize, T: Immutable => Immutable for [T; N]);
715 unsafe_impl!(const N: usize, T: TryFromBytes => TryFromBytes for [T; N]; |c: Maybe<[T; N]>| {
716 // Note that this call may panic, but it would still be sound even if it
717 // did. `is_bit_valid` does not promise that it will not panic (in fact,
718 // it explicitly warns that it's a possibility), and we have not
719 // violated any safety invariants that we must fix before returning.
720 <[T] as TryFromBytes>::is_bit_valid(c.as_slice())
721 });
722 unsafe_impl!(const N: usize, T: FromZeros => FromZeros for [T; N]);
723 unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]);
724 unsafe_impl!(const N: usize, T: IntoBytes => IntoBytes for [T; N]);
725 unsafe_impl!(const N: usize, T: Unaligned => Unaligned for [T; N]);
726 assert_unaligned!([(); 0], [(); 1], [u8; 0], [u8; 1]);
727 unsafe_impl!(T: Immutable => Immutable for [T]);
728 unsafe_impl!(T: TryFromBytes => TryFromBytes for [T]; |c: Maybe<[T]>| {
729 // SAFETY: Per the reference [1]:
730 //
731 // An array of `[T; N]` has a size of `size_of::<T>() * N` and the
732 // same alignment of `T`. Arrays are laid out so that the zero-based
733 // `nth` element of the array is offset from the start of the array by
734 // `n * size_of::<T>()` bytes.
735 //
736 // ...
737 //
738 // Slices have the same layout as the section of the array they slice.
739 //
740 // In other words, the layout of a `[T] is a sequence of `T`s laid out
741 // back-to-back with no bytes in between. If all elements in `candidate`
742 // are `is_bit_valid`, so too is `candidate`.
743 //
744 // Note that any of the below calls may panic, but it would still be
745 // sound even if it did. `is_bit_valid` does not promise that it will
746 // not panic (in fact, it explicitly warns that it's a possibility), and
747 // we have not violated any safety invariants that we must fix before
748 // returning.
749 c.iter().all(<T as TryFromBytes>::is_bit_valid)
750 });
751 unsafe_impl!(T: FromZeros => FromZeros for [T]);
752 unsafe_impl!(T: FromBytes => FromBytes for [T]);
753 unsafe_impl!(T: IntoBytes => IntoBytes for [T]);
754 unsafe_impl!(T: Unaligned => Unaligned for [T]);
755}
756safety_comment! {
757 /// SAFETY:
758 /// - `Immutable`: Raw pointers do not contain any `UnsafeCell`s.
759 /// - `FromZeros`: For thin pointers (note that `T: Sized`), the zero
760 /// pointer is considered "null". [1] No operations which require
761 /// provenance are legal on null pointers, so this is not a footgun.
762 /// - `TryFromBytes`: By the same reasoning as for `FromZeroes`, we can
763 /// implement `TryFromBytes` for thin pointers provided that
764 /// [`TryFromByte::is_bit_valid`] only produces `true` for zeroed bytes.
765 ///
766 /// NOTE(#170): Implementing `FromBytes` and `IntoBytes` for raw pointers
767 /// would be sound, but carries provenance footguns. We want to support
768 /// `FromBytes` and `IntoBytes` for raw pointers eventually, but we are
769 /// holding off until we can figure out how to address those footguns.
770 ///
771 /// [1] TODO(https://github.com/rust-lang/rust/pull/116988): Cite the
772 /// documentation once this PR lands.
773 unsafe_impl!(T: ?Sized => Immutable for *const T);
774 unsafe_impl!(T: ?Sized => Immutable for *mut T);
775 unsafe_impl!(T => TryFromBytes for *const T; |c: Maybe<*const T>| {
776 pointer::is_zeroed(c)
777 });
778 unsafe_impl!(T => FromZeros for *const T);
779 unsafe_impl!(T => TryFromBytes for *mut T; |c: Maybe<*const T>| {
780 pointer::is_zeroed(c)
781 });
782 unsafe_impl!(T => FromZeros for *mut T);
783}
784
785safety_comment! {
786 /// SAFETY:
787 /// `NonNull<T>` self-evidently does not contain `UnsafeCell`s. This is not
788 /// a proof, but we are accepting this as a known risk per #1358.
789 unsafe_impl!(T: ?Sized => Immutable for NonNull<T>);
790}
791
792safety_comment! {
793 /// SAFETY:
794 /// Reference types do not contain any `UnsafeCell`s.
795 unsafe_impl!(T: ?Sized => Immutable for &'_ T);
796 unsafe_impl!(T: ?Sized => Immutable for &'_ mut T);
797}
798
799safety_comment! {
800 /// SAFETY:
801 /// `Option` is not `#[non_exhaustive]` [1], which means that the types in
802 /// its variants cannot change, and no new variants can be added.
803 /// `Option<T>` does not contain any `UnsafeCell`s outside of `T`. [1]
804 ///
805 /// [1] https://doc.rust-lang.org/core/option/enum.Option.html
806 unsafe_impl!(T: Immutable => Immutable for Option<T>);
807}
808
809// SIMD support
810//
811// Per the Unsafe Code Guidelines Reference [1]:
812//
813// Packed SIMD vector types are `repr(simd)` homogeneous tuple-structs
814// containing `N` elements of type `T` where `N` is a power-of-two and the
815// size and alignment requirements of `T` are equal:
816//
817// ```rust
818// #[repr(simd)]
819// struct Vector<T, N>(T_0, ..., T_(N - 1));
820// ```
821//
822// ...
823//
824// The size of `Vector` is `N * size_of::<T>()` and its alignment is an
825// implementation-defined function of `T` and `N` greater than or equal to
826// `align_of::<T>()`.
827//
828// ...
829//
830// Vector elements are laid out in source field order, enabling random access
831// to vector elements by reinterpreting the vector as an array:
832//
833// ```rust
834// union U {
835// vec: Vector<T, N>,
836// arr: [T; N]
837// }
838//
839// assert_eq!(size_of::<Vector<T, N>>(), size_of::<[T; N]>());
840// assert!(align_of::<Vector<T, N>>() >= align_of::<[T; N]>());
841//
842// unsafe {
843// let u = U { vec: Vector<T, N>(t_0, ..., t_(N - 1)) };
844//
845// assert_eq!(u.vec.0, u.arr[0]);
846// // ...
847// assert_eq!(u.vec.(N - 1), u.arr[N - 1]);
848// }
849// ```
850//
851// Given this background, we can observe that:
852// - The size and bit pattern requirements of a SIMD type are equivalent to the
853// equivalent array type. Thus, for any SIMD type whose primitive `T` is
854// `Immutable`, `TryFromBytes`, `FromZeros`, `FromBytes`, or `IntoBytes`, that
855// SIMD type is also `Immutable`, `TryFromBytes`, `FromZeros`, `FromBytes`, or
856// `IntoBytes` respectively.
857// - Since no upper bound is placed on the alignment, no SIMD type can be
858// guaranteed to be `Unaligned`.
859//
860// Also per [1]:
861//
862// This chapter represents the consensus from issue #38. The statements in
863// here are not (yet) "guaranteed" not to change until an RFC ratifies them.
864//
865// See issue #38 [2]. While this behavior is not technically guaranteed, the
866// likelihood that the behavior will change such that SIMD types are no longer
867// `TryFromBytes`, `FromZeros`, `FromBytes`, or `IntoBytes` is next to zero, as
868// that would defeat the entire purpose of SIMD types. Nonetheless, we put this
869// behavior behind the `simd` Cargo feature, which requires consumers to opt
870// into this stability hazard.
871//
872// [1] https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html
873// [2] https://github.com/rust-lang/unsafe-code-guidelines/issues/38
874#[cfg(feature = "simd")]
875#[cfg_attr(doc_cfg, doc(cfg(feature = "simd")))]
876mod simd {
877 /// Defines a module which implements `TryFromBytes`, `FromZeros`,
878 /// `FromBytes`, and `IntoBytes` for a set of types from a module in
879 /// `core::arch`.
880 ///
881 /// `$arch` is both the name of the defined module and the name of the
882 /// module in `core::arch`, and `$typ` is the list of items from that module
883 /// to implement `FromZeros`, `FromBytes`, and `IntoBytes` for.
884 #[allow(unused_macros)] // `allow(unused_macros)` is needed because some
885 // target/feature combinations don't emit any impls
886 // and thus don't use this macro.
887 macro_rules! simd_arch_mod {
888 (#[cfg $cfg:tt] $arch:ident, $mod:ident, $($typ:ident),*) => {
889 #[cfg $cfg]
890 #[cfg_attr(doc_cfg, doc(cfg $cfg))]
891 mod $mod {
892 use core::arch::$arch::{$($typ),*};
893
894 use crate::*;
895 impl_known_layout!($($typ),*);
896 safety_comment! {
897 /// SAFETY:
898 /// See comment on module definition for justification.
899 $( unsafe_impl!($typ: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); )*
900 }
901 }
902 };
903 }
904
905 #[rustfmt::skip]
906 const _: () = {
907 simd_arch_mod!(
908 #[cfg(target_arch = "x86")]
909 x86, x86, __m128, __m128d, __m128i, __m256, __m256d, __m256i
910 );
911 simd_arch_mod!(
912 #[cfg(all(feature = "simd-nightly", target_arch = "x86"))]
913 x86, x86_nightly, __m512bh, __m512, __m512d, __m512i
914 );
915 simd_arch_mod!(
916 #[cfg(target_arch = "x86_64")]
917 x86_64, x86_64, __m128, __m128d, __m128i, __m256, __m256d, __m256i
918 );
919 simd_arch_mod!(
920 #[cfg(all(feature = "simd-nightly", target_arch = "x86_64"))]
921 x86_64, x86_64_nightly, __m512bh, __m512, __m512d, __m512i
922 );
923 simd_arch_mod!(
924 #[cfg(target_arch = "wasm32")]
925 wasm32, wasm32, v128
926 );
927 simd_arch_mod!(
928 #[cfg(all(feature = "simd-nightly", target_arch = "powerpc"))]
929 powerpc, powerpc, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long
930 );
931 simd_arch_mod!(
932 #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))]
933 powerpc64, powerpc64, vector_bool_long, vector_double, vector_signed_long, vector_unsigned_long
934 );
935 #[cfg(zerocopy_aarch64_simd)]
936 simd_arch_mod!(
937 // NOTE(https://github.com/rust-lang/stdarch/issues/1484): NEON intrinsics are currently
938 // broken on big-endian platforms.
939 #[cfg(all(target_arch = "aarch64", target_endian = "little"))]
940 aarch64, aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t,
941 int8x8x3_t, int8x8x4_t, int8x16_t, int8x16x2_t, int8x16x3_t, int8x16x4_t, int16x4_t,
942 int16x8_t, int32x2_t, int32x4_t, int64x1_t, int64x2_t, poly8x8_t, poly8x8x2_t, poly8x8x3_t,
943 poly8x8x4_t, poly8x16_t, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t, poly16x4_t, poly16x8_t,
944 poly64x1_t, poly64x2_t, uint8x8_t, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t, uint8x16_t,
945 uint8x16x2_t, uint8x16x3_t, uint8x16x4_t, uint16x4_t, uint16x8_t, uint32x2_t, uint32x4_t,
946 uint64x1_t, uint64x2_t
947 );
948 simd_arch_mod!(
949 #[cfg(all(feature = "simd-nightly", target_arch = "arm"))]
950 arm, arm, int8x4_t, uint8x4_t
951 );
952 };
953}
954
955#[cfg(test)]
956mod tests {
957 use super::*;
958
959 #[test]
960 fn test_impls() {
961 // A type that can supply test cases for testing
962 // `TryFromBytes::is_bit_valid`. All types passed to `assert_impls!`
963 // must implement this trait; that macro uses it to generate runtime
964 // tests for `TryFromBytes` impls.
965 //
966 // All `T: FromBytes` types are provided with a blanket impl. Other
967 // types must implement `TryFromBytesTestable` directly (ie using
968 // `impl_try_from_bytes_testable!`).
969 trait TryFromBytesTestable {
970 fn with_passing_test_cases<F: Fn(Box<Self>)>(f: F);
971 fn with_failing_test_cases<F: Fn(&mut [u8])>(f: F);
972 }
973
974 impl<T: FromBytes> TryFromBytesTestable for T {
975 fn with_passing_test_cases<F: Fn(Box<Self>)>(f: F) {
976 // Test with a zeroed value.
977 f(Self::new_box_zeroed().unwrap());
978
979 let ffs = {
980 let mut t = Self::new_zeroed();
981 let ptr: *mut T = &mut t;
982 // SAFETY: `T: FromBytes`
983 unsafe { ptr::write_bytes(ptr.cast::<u8>(), 0xFF, mem::size_of::<T>()) };
984 t
985 };
986
987 // Test with a value initialized with 0xFF.
988 f(Box::new(ffs));
989 }
990
991 fn with_failing_test_cases<F: Fn(&mut [u8])>(_f: F) {}
992 }
993
994 macro_rules! impl_try_from_bytes_testable_for_null_pointer_optimization {
995 ($($tys:ty),*) => {
996 $(
997 impl TryFromBytesTestable for Option<$tys> {
998 fn with_passing_test_cases<F: Fn(Box<Self>)>(f: F) {
999 // Test with a zeroed value.
1000 f(Box::new(None));
1001 }
1002
1003 fn with_failing_test_cases<F: Fn(&mut [u8])>(f: F) {
1004 for pos in 0..mem::size_of::<Self>() {
1005 let mut bytes = [0u8; mem::size_of::<Self>()];
1006 bytes[pos] = 0x01;
1007 f(&mut bytes[..]);
1008 }
1009 }
1010 }
1011 )*
1012 };
1013 }
1014
1015 // Implements `TryFromBytesTestable`.
1016 macro_rules! impl_try_from_bytes_testable {
1017 // Base case for recursion (when the list of types has run out).
1018 (=> @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => {};
1019 // Implements for type(s) with no type parameters.
1020 ($ty:ty $(,$tys:ty)* => @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => {
1021 impl TryFromBytesTestable for $ty {
1022 impl_try_from_bytes_testable!(
1023 @methods @success $($success_case),*
1024 $(, @failure $($failure_case),*)?
1025 );
1026 }
1027 impl_try_from_bytes_testable!($($tys),* => @success $($success_case),* $(, @failure $($failure_case),*)?);
1028 };
1029 // Implements for multiple types with no type parameters.
1030 ($($($ty:ty),* => @success $($success_case:expr), * $(, @failure $($failure_case:expr),*)?;)*) => {
1031 $(
1032 impl_try_from_bytes_testable!($($ty),* => @success $($success_case),* $(, @failure $($failure_case),*)*);
1033 )*
1034 };
1035 // Implements only the methods; caller must invoke this from inside
1036 // an impl block.
1037 (@methods @success $($success_case:expr),* $(, @failure $($failure_case:expr),*)?) => {
1038 fn with_passing_test_cases<F: Fn(Box<Self>)>(_f: F) {
1039 $(
1040 _f(Box::<Self>::from($success_case));
1041 )*
1042 }
1043
1044 fn with_failing_test_cases<F: Fn(&mut [u8])>(_f: F) {
1045 $($(
1046 let mut case = $failure_case;
1047 _f(case.as_mut_bytes());
1048 )*)?
1049 }
1050 };
1051 }
1052
1053 impl_try_from_bytes_testable_for_null_pointer_optimization!(
1054 Box<UnsafeCell<NotZerocopy>>,
1055 &'static UnsafeCell<NotZerocopy>,
1056 &'static mut UnsafeCell<NotZerocopy>,
1057 NonNull<UnsafeCell<NotZerocopy>>,
1058 fn(),
1059 FnManyArgs,
1060 extern "C" fn(),
1061 ECFnManyArgs
1062 );
1063
1064 macro_rules! bx {
1065 ($e:expr) => {
1066 Box::new($e)
1067 };
1068 }
1069
1070 // Note that these impls are only for types which are not `FromBytes`.
1071 // `FromBytes` types are covered by a preceding blanket impl.
1072 impl_try_from_bytes_testable!(
1073 bool => @success true, false,
1074 @failure 2u8, 3u8, 0xFFu8;
1075 char => @success '\u{0}', '\u{D7FF}', '\u{E000}', '\u{10FFFF}',
1076 @failure 0xD800u32, 0xDFFFu32, 0x110000u32;
1077 str => @success "", "hello", "❤️🧡💛💚💙💜",
1078 @failure [0, 159, 146, 150];
1079 [u8] => @success vec![].into_boxed_slice(), vec![0, 1, 2].into_boxed_slice();
1080 NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32,
1081 NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128,
1082 NonZeroUsize, NonZeroIsize
1083 => @success Self::new(1).unwrap(),
1084 // Doing this instead of `0` ensures that we always satisfy
1085 // the size and alignment requirements of `Self` (whereas `0`
1086 // may be any integer type with a different size or alignment
1087 // than some `NonZeroXxx` types).
1088 @failure Option::<Self>::None;
1089 [bool; 0] => @success [];
1090 [bool; 1]
1091 => @success [true], [false],
1092 @failure [2u8], [3u8], [0xFFu8];
1093 [bool]
1094 => @success vec![true, false].into_boxed_slice(), vec![false, true].into_boxed_slice(),
1095 @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8];
1096 Unalign<bool>
1097 => @success Unalign::new(false), Unalign::new(true),
1098 @failure 2u8, 0xFFu8;
1099 ManuallyDrop<bool>
1100 => @success ManuallyDrop::new(false), ManuallyDrop::new(true),
1101 @failure 2u8, 0xFFu8;
1102 ManuallyDrop<[u8]>
1103 => @success bx!(ManuallyDrop::new([])), bx!(ManuallyDrop::new([0u8])), bx!(ManuallyDrop::new([0u8, 1u8]));
1104 ManuallyDrop<[bool]>
1105 => @success bx!(ManuallyDrop::new([])), bx!(ManuallyDrop::new([false])), bx!(ManuallyDrop::new([false, true])),
1106 @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8];
1107 ManuallyDrop<[UnsafeCell<u8>]>
1108 => @success bx!(ManuallyDrop::new([UnsafeCell::new(0)])), bx!(ManuallyDrop::new([UnsafeCell::new(0), UnsafeCell::new(1)]));
1109 ManuallyDrop<[UnsafeCell<bool>]>
1110 => @success bx!(ManuallyDrop::new([UnsafeCell::new(false)])), bx!(ManuallyDrop::new([UnsafeCell::new(false), UnsafeCell::new(true)])),
1111 @failure [2u8], [3u8], [0xFFu8], [0u8, 1u8, 2u8];
1112 Wrapping<bool>
1113 => @success Wrapping(false), Wrapping(true),
1114 @failure 2u8, 0xFFu8;
1115 *const NotZerocopy
1116 => @success ptr::null::<NotZerocopy>(),
1117 @failure [0x01; mem::size_of::<*const NotZerocopy>()];
1118 *mut NotZerocopy
1119 => @success ptr::null_mut::<NotZerocopy>(),
1120 @failure [0x01; mem::size_of::<*mut NotZerocopy>()];
1121 );
1122
1123 // Use the trick described in [1] to allow us to call methods
1124 // conditional on certain trait bounds.
1125 //
1126 // In all of these cases, methods return `Option<R>`, where `R` is the
1127 // return type of the method we're conditionally calling. The "real"
1128 // implementations (the ones defined in traits using `&self`) return
1129 // `Some`, and the default implementations (the ones defined as inherent
1130 // methods using `&mut self`) return `None`.
1131 //
1132 // [1] https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md
1133 mod autoref_trick {
1134 use super::*;
1135
1136 pub(super) struct AutorefWrapper<T: ?Sized>(pub(super) PhantomData<T>);
1137
1138 pub(super) trait TestIsBitValidShared<T: ?Sized> {
1139 #[allow(clippy::needless_lifetimes)]
1140 fn test_is_bit_valid_shared<
1141 'ptr,
1142 A: invariant::Aliasing + invariant::AtLeast<invariant::Shared>,
1143 >(
1144 &self,
1145 candidate: Maybe<'ptr, T, A>,
1146 ) -> Option<bool>;
1147 }
1148
1149 impl<T: TryFromBytes + Immutable + ?Sized> TestIsBitValidShared<T> for AutorefWrapper<T> {
1150 #[allow(clippy::needless_lifetimes)]
1151 fn test_is_bit_valid_shared<
1152 'ptr,
1153 A: invariant::Aliasing + invariant::AtLeast<invariant::Shared>,
1154 >(
1155 &self,
1156 candidate: Maybe<'ptr, T, A>,
1157 ) -> Option<bool> {
1158 Some(T::is_bit_valid(candidate))
1159 }
1160 }
1161
1162 pub(super) trait TestTryFromRef<T: ?Sized> {
1163 #[allow(clippy::needless_lifetimes)]
1164 fn test_try_from_ref<'bytes>(
1165 &self,
1166 bytes: &'bytes [u8],
1167 ) -> Option<Option<&'bytes T>>;
1168 }
1169
1170 impl<T: TryFromBytes + Immutable + KnownLayout + ?Sized> TestTryFromRef<T> for AutorefWrapper<T> {
1171 #[allow(clippy::needless_lifetimes)]
1172 fn test_try_from_ref<'bytes>(
1173 &self,
1174 bytes: &'bytes [u8],
1175 ) -> Option<Option<&'bytes T>> {
1176 Some(T::try_ref_from_bytes(bytes).ok())
1177 }
1178 }
1179
1180 pub(super) trait TestTryReadFrom<T> {
1181 fn test_try_read_from(&self, bytes: &[u8]) -> Option<Option<T>>;
1182 }
1183
1184 impl<T: TryFromBytes> TestTryReadFrom<T> for AutorefWrapper<T> {
1185 fn test_try_read_from(&self, bytes: &[u8]) -> Option<Option<T>> {
1186 Some(T::try_read_from_bytes(bytes).ok())
1187 }
1188 }
1189
1190 pub(super) trait TestAsBytes<T: ?Sized> {
1191 #[allow(clippy::needless_lifetimes)]
1192 fn test_as_bytes<'slf, 't>(&'slf self, t: &'t T) -> Option<&'t [u8]>;
1193 }
1194
1195 impl<T: IntoBytes + Immutable + ?Sized> TestAsBytes<T> for AutorefWrapper<T> {
1196 #[allow(clippy::needless_lifetimes)]
1197 fn test_as_bytes<'slf, 't>(&'slf self, t: &'t T) -> Option<&'t [u8]> {
1198 Some(t.as_bytes())
1199 }
1200 }
1201 }
1202
1203 use autoref_trick::*;
1204
1205 // Asserts that `$ty` is one of a list of types which are allowed to not
1206 // provide a "real" implementation for `$fn_name`. Since the
1207 // `autoref_trick` machinery fails silently, this allows us to ensure
1208 // that the "default" impls are only being used for types which we
1209 // expect.
1210 //
1211 // Note that, since this is a runtime test, it is possible to have an
1212 // allowlist which is too restrictive if the function in question is
1213 // never called for a particular type. For example, if `as_bytes` is not
1214 // supported for a particular type, and so `test_as_bytes` returns
1215 // `None`, methods such as `test_try_from_ref` may never be called for
1216 // that type. As a result, it's possible that, for example, adding
1217 // `as_bytes` support for a type would cause other allowlist assertions
1218 // to fail. This means that allowlist assertion failures should not
1219 // automatically be taken as a sign of a bug.
1220 macro_rules! assert_on_allowlist {
1221 ($fn_name:ident($ty:ty) $(: $($tys:ty),*)?) => {{
1222 use core::any::TypeId;
1223
1224 let allowlist: &[TypeId] = &[ $($(TypeId::of::<$tys>()),*)? ];
1225 let allowlist_names: &[&str] = &[ $($(stringify!($tys)),*)? ];
1226
1227 let id = TypeId::of::<$ty>();
1228 assert!(allowlist.contains(&id), "{} is not on allowlist for {}: {:?}", stringify!($ty), stringify!($fn_name), allowlist_names);
1229 }};
1230 }
1231
1232 // Asserts that `$ty` implements any `$trait` and doesn't implement any
1233 // `!$trait`. Note that all `$trait`s must come before any `!$trait`s.
1234 //
1235 // For `T: TryFromBytes`, uses `TryFromBytesTestable` to test success
1236 // and failure cases.
1237 macro_rules! assert_impls {
1238 ($ty:ty: TryFromBytes) => {
1239 // "Default" implementations that match the "real"
1240 // implementations defined in the `autoref_trick` module above.
1241 #[allow(unused, non_local_definitions)]
1242 impl AutorefWrapper<$ty> {
1243 #[allow(clippy::needless_lifetimes)]
1244 fn test_is_bit_valid_shared<'ptr, A: invariant::Aliasing + invariant::AtLeast<invariant::Shared>>(
1245 &mut self,
1246 candidate: Maybe<'ptr, $ty, A>,
1247 ) -> Option<bool> {
1248 assert_on_allowlist!(
1249 test_is_bit_valid_shared($ty):
1250 ManuallyDrop<UnsafeCell<()>>,
1251 ManuallyDrop<[UnsafeCell<u8>]>,
1252 ManuallyDrop<[UnsafeCell<bool>]>,
1253 MaybeUninit<NotZerocopy>,
1254 MaybeUninit<UnsafeCell<()>>,
1255 Wrapping<UnsafeCell<()>>
1256 );
1257
1258 None
1259 }
1260
1261 #[allow(clippy::needless_lifetimes)]
1262 fn test_try_from_ref<'bytes>(&mut self, _bytes: &'bytes [u8]) -> Option<Option<&'bytes $ty>> {
1263 assert_on_allowlist!(
1264 test_try_from_ref($ty):
1265 ManuallyDrop<[UnsafeCell<bool>]>
1266 );
1267
1268 None
1269 }
1270
1271 fn test_try_read_from(&mut self, _bytes: &[u8]) -> Option<Option<&$ty>> {
1272 assert_on_allowlist!(
1273 test_try_read_from($ty):
1274 str,
1275 ManuallyDrop<[u8]>,
1276 ManuallyDrop<[bool]>,
1277 ManuallyDrop<[UnsafeCell<bool>]>,
1278 [u8],
1279 [bool]
1280 );
1281
1282 None
1283 }
1284
1285 fn test_as_bytes(&mut self, _t: &$ty) -> Option<&[u8]> {
1286 assert_on_allowlist!(
1287 test_as_bytes($ty):
1288 Option<&'static UnsafeCell<NotZerocopy>>,
1289 Option<&'static mut UnsafeCell<NotZerocopy>>,
1290 Option<NonNull<UnsafeCell<NotZerocopy>>>,
1291 Option<Box<UnsafeCell<NotZerocopy>>>,
1292 Option<fn()>,
1293 Option<FnManyArgs>,
1294 Option<extern "C" fn()>,
1295 Option<ECFnManyArgs>,
1296 MaybeUninit<u8>,
1297 MaybeUninit<NotZerocopy>,
1298 MaybeUninit<UnsafeCell<()>>,
1299 ManuallyDrop<UnsafeCell<()>>,
1300 ManuallyDrop<[UnsafeCell<u8>]>,
1301 ManuallyDrop<[UnsafeCell<bool>]>,
1302 Wrapping<UnsafeCell<()>>,
1303 *const NotZerocopy,
1304 *mut NotZerocopy
1305 );
1306
1307 None
1308 }
1309 }
1310
1311 <$ty as TryFromBytesTestable>::with_passing_test_cases(|mut val| {
1312 // TODO(#494): These tests only get exercised for types
1313 // which are `IntoBytes`. Once we implement #494, we should
1314 // be able to support non-`IntoBytes` types by zeroing
1315 // padding.
1316
1317 // We define `w` and `ww` since, in the case of the inherent
1318 // methods, Rust thinks they're both borrowed mutably at the
1319 // same time (given how we use them below). If we just
1320 // defined a single `w` and used it for multiple operations,
1321 // this would conflict.
1322 //
1323 // We `#[allow(unused_mut]` for the cases where the "real"
1324 // impls are used, which take `&self`.
1325 #[allow(unused_mut)]
1326 let (mut w, mut ww) = (AutorefWrapper::<$ty>(PhantomData), AutorefWrapper::<$ty>(PhantomData));
1327
1328 let c = Ptr::from_ref(&*val);
1329 let c = c.forget_aligned();
1330 // SAFETY: TODO(#899): This is unsound. `$ty` is not
1331 // necessarily `IntoBytes`, but that's the corner we've
1332 // backed ourselves into by using `Ptr::from_ref`.
1333 let c = unsafe { c.assume_initialized() };
1334 let res = w.test_is_bit_valid_shared(c);
1335 if let Some(res) = res {
1336 assert!(res, "{}::is_bit_valid({:?}) (shared `Ptr`): got false, expected true", stringify!($ty), val);
1337 }
1338
1339 let c = Ptr::from_mut(&mut *val);
1340 let c = c.forget_aligned();
1341 // SAFETY: TODO(#899): This is unsound. `$ty` is not
1342 // necessarily `IntoBytes`, but that's the corner we've
1343 // backed ourselves into by using `Ptr::from_ref`.
1344 let c = unsafe { c.assume_initialized() };
1345 let res = <$ty as TryFromBytes>::is_bit_valid(c);
1346 assert!(res, "{}::is_bit_valid({:?}) (exclusive `Ptr`): got false, expected true", stringify!($ty), val);
1347
1348 // `bytes` is `Some(val.as_bytes())` if `$ty: IntoBytes +
1349 // Immutable` and `None` otherwise.
1350 let bytes = w.test_as_bytes(&*val);
1351
1352 // The inner closure returns
1353 // `Some($ty::try_ref_from_bytes(bytes))` if `$ty:
1354 // Immutable` and `None` otherwise.
1355 let res = bytes.and_then(|bytes| ww.test_try_from_ref(bytes));
1356 if let Some(res) = res {
1357 assert!(res.is_some(), "{}::try_ref_from_bytes({:?}): got `None`, expected `Some`", stringify!($ty), val);
1358 }
1359
1360 if let Some(bytes) = bytes {
1361 // We need to get a mutable byte slice, and so we clone
1362 // into a `Vec`. However, we also need these bytes to
1363 // satisfy `$ty`'s alignment requirement, which isn't
1364 // guaranteed for `Vec<u8>`. In order to get around
1365 // this, we create a `Vec` which is twice as long as we
1366 // need. There is guaranteed to be an aligned byte range
1367 // of size `size_of_val(val)` within that range.
1368 let val = &*val;
1369 let size = mem::size_of_val(val);
1370 let align = mem::align_of_val(val);
1371
1372 let mut vec = bytes.to_vec();
1373 vec.extend(bytes);
1374 let slc = vec.as_slice();
1375 let offset = slc.as_ptr().align_offset(align);
1376 let bytes_mut = &mut vec.as_mut_slice()[offset..offset+size];
1377 bytes_mut.copy_from_slice(bytes);
1378
1379 let res = <$ty as TryFromBytes>::try_mut_from_bytes(bytes_mut);
1380 assert!(res.is_ok(), "{}::try_mut_from_bytes({:?}): got `Err`, expected `Ok`", stringify!($ty), val);
1381 }
1382
1383 let res = bytes.and_then(|bytes| ww.test_try_read_from(bytes));
1384 if let Some(res) = res {
1385 assert!(res.is_some(), "{}::try_read_from_bytes({:?}): got `None`, expected `Some`", stringify!($ty), val);
1386 }
1387 });
1388 #[allow(clippy::as_conversions)]
1389 <$ty as TryFromBytesTestable>::with_failing_test_cases(|c| {
1390 #[allow(unused_mut)] // For cases where the "real" impls are used, which take `&self`.
1391 let mut w = AutorefWrapper::<$ty>(PhantomData);
1392
1393 // This is `Some($ty::try_ref_from_bytes(c))` if `$ty:
1394 // Immutable` and `None` otherwise.
1395 let res = w.test_try_from_ref(c);
1396 if let Some(res) = res {
1397 assert!(res.is_none(), "{}::try_ref_from_bytes({:?}): got Some, expected None", stringify!($ty), c);
1398 }
1399
1400 let res = <$ty as TryFromBytes>::try_mut_from_bytes(c);
1401 assert!(res.is_err(), "{}::try_mut_from_bytes({:?}): got Ok, expected Err", stringify!($ty), c);
1402
1403 let res = w.test_try_read_from(c);
1404 if let Some(res) = res {
1405 assert!(res.is_none(), "{}::try_read_from_bytes({:?}): got Some, expected None", stringify!($ty), c);
1406 }
1407 });
1408
1409 #[allow(dead_code)]
1410 const _: () = { static_assertions::assert_impl_all!($ty: TryFromBytes); };
1411 };
1412 ($ty:ty: $trait:ident) => {
1413 #[allow(dead_code)]
1414 const _: () = { static_assertions::assert_impl_all!($ty: $trait); };
1415 };
1416 ($ty:ty: !$trait:ident) => {
1417 #[allow(dead_code)]
1418 const _: () = { static_assertions::assert_not_impl_any!($ty: $trait); };
1419 };
1420 ($ty:ty: $($trait:ident),* $(,)? $(!$negative_trait:ident),*) => {
1421 $(
1422 assert_impls!($ty: $trait);
1423 )*
1424
1425 $(
1426 assert_impls!($ty: !$negative_trait);
1427 )*
1428 };
1429 }
1430
1431 // NOTE: The negative impl assertions here are not necessarily
1432 // prescriptive. They merely serve as change detectors to make sure
1433 // we're aware of what trait impls are getting added with a given
1434 // change. Of course, some impls would be invalid (e.g., `bool:
1435 // FromBytes`), and so this change detection is very important.
1436
1437 assert_impls!(
1438 (): KnownLayout,
1439 Immutable,
1440 TryFromBytes,
1441 FromZeros,
1442 FromBytes,
1443 IntoBytes,
1444 Unaligned
1445 );
1446 assert_impls!(
1447 u8: KnownLayout,
1448 Immutable,
1449 TryFromBytes,
1450 FromZeros,
1451 FromBytes,
1452 IntoBytes,
1453 Unaligned
1454 );
1455 assert_impls!(
1456 i8: KnownLayout,
1457 Immutable,
1458 TryFromBytes,
1459 FromZeros,
1460 FromBytes,
1461 IntoBytes,
1462 Unaligned
1463 );
1464 assert_impls!(
1465 u16: KnownLayout,
1466 Immutable,
1467 TryFromBytes,
1468 FromZeros,
1469 FromBytes,
1470 IntoBytes,
1471 !Unaligned
1472 );
1473 assert_impls!(
1474 i16: KnownLayout,
1475 Immutable,
1476 TryFromBytes,
1477 FromZeros,
1478 FromBytes,
1479 IntoBytes,
1480 !Unaligned
1481 );
1482 assert_impls!(
1483 u32: KnownLayout,
1484 Immutable,
1485 TryFromBytes,
1486 FromZeros,
1487 FromBytes,
1488 IntoBytes,
1489 !Unaligned
1490 );
1491 assert_impls!(
1492 i32: KnownLayout,
1493 Immutable,
1494 TryFromBytes,
1495 FromZeros,
1496 FromBytes,
1497 IntoBytes,
1498 !Unaligned
1499 );
1500 assert_impls!(
1501 u64: KnownLayout,
1502 Immutable,
1503 TryFromBytes,
1504 FromZeros,
1505 FromBytes,
1506 IntoBytes,
1507 !Unaligned
1508 );
1509 assert_impls!(
1510 i64: KnownLayout,
1511 Immutable,
1512 TryFromBytes,
1513 FromZeros,
1514 FromBytes,
1515 IntoBytes,
1516 !Unaligned
1517 );
1518 assert_impls!(
1519 u128: KnownLayout,
1520 Immutable,
1521 TryFromBytes,
1522 FromZeros,
1523 FromBytes,
1524 IntoBytes,
1525 !Unaligned
1526 );
1527 assert_impls!(
1528 i128: KnownLayout,
1529 Immutable,
1530 TryFromBytes,
1531 FromZeros,
1532 FromBytes,
1533 IntoBytes,
1534 !Unaligned
1535 );
1536 assert_impls!(
1537 usize: KnownLayout,
1538 Immutable,
1539 TryFromBytes,
1540 FromZeros,
1541 FromBytes,
1542 IntoBytes,
1543 !Unaligned
1544 );
1545 assert_impls!(
1546 isize: KnownLayout,
1547 Immutable,
1548 TryFromBytes,
1549 FromZeros,
1550 FromBytes,
1551 IntoBytes,
1552 !Unaligned
1553 );
1554 assert_impls!(
1555 f32: KnownLayout,
1556 Immutable,
1557 TryFromBytes,
1558 FromZeros,
1559 FromBytes,
1560 IntoBytes,
1561 !Unaligned
1562 );
1563 assert_impls!(
1564 f64: KnownLayout,
1565 Immutable,
1566 TryFromBytes,
1567 FromZeros,
1568 FromBytes,
1569 IntoBytes,
1570 !Unaligned
1571 );
1572
1573 assert_impls!(
1574 bool: KnownLayout,
1575 Immutable,
1576 TryFromBytes,
1577 FromZeros,
1578 IntoBytes,
1579 Unaligned,
1580 !FromBytes
1581 );
1582 assert_impls!(
1583 char: KnownLayout,
1584 Immutable,
1585 TryFromBytes,
1586 FromZeros,
1587 IntoBytes,
1588 !FromBytes,
1589 !Unaligned
1590 );
1591 assert_impls!(
1592 str: KnownLayout,
1593 Immutable,
1594 TryFromBytes,
1595 FromZeros,
1596 IntoBytes,
1597 Unaligned,
1598 !FromBytes
1599 );
1600
1601 assert_impls!(
1602 NonZeroU8: KnownLayout,
1603 Immutable,
1604 TryFromBytes,
1605 IntoBytes,
1606 Unaligned,
1607 !FromZeros,
1608 !FromBytes
1609 );
1610 assert_impls!(
1611 NonZeroI8: KnownLayout,
1612 Immutable,
1613 TryFromBytes,
1614 IntoBytes,
1615 Unaligned,
1616 !FromZeros,
1617 !FromBytes
1618 );
1619 assert_impls!(
1620 NonZeroU16: KnownLayout,
1621 Immutable,
1622 TryFromBytes,
1623 IntoBytes,
1624 !FromBytes,
1625 !Unaligned
1626 );
1627 assert_impls!(
1628 NonZeroI16: KnownLayout,
1629 Immutable,
1630 TryFromBytes,
1631 IntoBytes,
1632 !FromBytes,
1633 !Unaligned
1634 );
1635 assert_impls!(
1636 NonZeroU32: KnownLayout,
1637 Immutable,
1638 TryFromBytes,
1639 IntoBytes,
1640 !FromBytes,
1641 !Unaligned
1642 );
1643 assert_impls!(
1644 NonZeroI32: KnownLayout,
1645 Immutable,
1646 TryFromBytes,
1647 IntoBytes,
1648 !FromBytes,
1649 !Unaligned
1650 );
1651 assert_impls!(
1652 NonZeroU64: KnownLayout,
1653 Immutable,
1654 TryFromBytes,
1655 IntoBytes,
1656 !FromBytes,
1657 !Unaligned
1658 );
1659 assert_impls!(
1660 NonZeroI64: KnownLayout,
1661 Immutable,
1662 TryFromBytes,
1663 IntoBytes,
1664 !FromBytes,
1665 !Unaligned
1666 );
1667 assert_impls!(
1668 NonZeroU128: KnownLayout,
1669 Immutable,
1670 TryFromBytes,
1671 IntoBytes,
1672 !FromBytes,
1673 !Unaligned
1674 );
1675 assert_impls!(
1676 NonZeroI128: KnownLayout,
1677 Immutable,
1678 TryFromBytes,
1679 IntoBytes,
1680 !FromBytes,
1681 !Unaligned
1682 );
1683 assert_impls!(
1684 NonZeroUsize: KnownLayout,
1685 Immutable,
1686 TryFromBytes,
1687 IntoBytes,
1688 !FromBytes,
1689 !Unaligned
1690 );
1691 assert_impls!(
1692 NonZeroIsize: KnownLayout,
1693 Immutable,
1694 TryFromBytes,
1695 IntoBytes,
1696 !FromBytes,
1697 !Unaligned
1698 );
1699
1700 assert_impls!(Option<NonZeroU8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
1701 assert_impls!(Option<NonZeroI8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
1702 assert_impls!(Option<NonZeroU16>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
1703 assert_impls!(Option<NonZeroI16>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
1704 assert_impls!(Option<NonZeroU32>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
1705 assert_impls!(Option<NonZeroI32>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
1706 assert_impls!(Option<NonZeroU64>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
1707 assert_impls!(Option<NonZeroI64>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
1708 assert_impls!(Option<NonZeroU128>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
1709 assert_impls!(Option<NonZeroI128>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
1710 assert_impls!(Option<NonZeroUsize>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
1711 assert_impls!(Option<NonZeroIsize>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned);
1712
1713 // Implements none of the ZC traits.
1714 struct NotZerocopy;
1715
1716 #[rustfmt::skip]
1717 type FnManyArgs = fn(
1718 NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
1719 ) -> (NotZerocopy, NotZerocopy);
1720
1721 // Allowed, because we're not actually using this type for FFI.
1722 #[allow(improper_ctypes_definitions)]
1723 #[rustfmt::skip]
1724 type ECFnManyArgs = extern "C" fn(
1725 NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
1726 ) -> (NotZerocopy, NotZerocopy);
1727
1728 #[cfg(feature = "alloc")]
1729 assert_impls!(Option<Box<UnsafeCell<NotZerocopy>>>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1730 assert_impls!(Option<Box<[UnsafeCell<NotZerocopy>]>>: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1731 assert_impls!(Option<&'static UnsafeCell<NotZerocopy>>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1732 assert_impls!(Option<&'static [UnsafeCell<NotZerocopy>]>: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1733 assert_impls!(Option<&'static mut UnsafeCell<NotZerocopy>>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1734 assert_impls!(Option<&'static mut [UnsafeCell<NotZerocopy>]>: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1735 assert_impls!(Option<NonNull<UnsafeCell<NotZerocopy>>>: KnownLayout, TryFromBytes, FromZeros, Immutable, !FromBytes, !IntoBytes, !Unaligned);
1736 assert_impls!(Option<NonNull<[UnsafeCell<NotZerocopy>]>>: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1737 assert_impls!(Option<fn()>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1738 assert_impls!(Option<FnManyArgs>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1739 assert_impls!(Option<extern "C" fn()>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1740 assert_impls!(Option<ECFnManyArgs>: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1741
1742 assert_impls!(PhantomData<NotZerocopy>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
1743 assert_impls!(PhantomData<UnsafeCell<()>>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
1744 assert_impls!(PhantomData<[u8]>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
1745
1746 assert_impls!(ManuallyDrop<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
1747 // This test is important because it allows us to test our hand-rolled
1748 // implementation of `<ManuallyDrop<T> as TryFromBytes>::is_bit_valid`.
1749 assert_impls!(ManuallyDrop<bool>: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes);
1750 assert_impls!(ManuallyDrop<[u8]>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
1751 // This test is important because it allows us to test our hand-rolled
1752 // implementation of `<ManuallyDrop<T> as TryFromBytes>::is_bit_valid`.
1753 assert_impls!(ManuallyDrop<[bool]>: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes);
1754 assert_impls!(ManuallyDrop<NotZerocopy>: !Immutable, !TryFromBytes, !KnownLayout, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1755 assert_impls!(ManuallyDrop<[NotZerocopy]>: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1756 assert_impls!(ManuallyDrop<UnsafeCell<()>>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable);
1757 assert_impls!(ManuallyDrop<[UnsafeCell<u8>]>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable);
1758 assert_impls!(ManuallyDrop<[UnsafeCell<bool>]>: KnownLayout, TryFromBytes, FromZeros, IntoBytes, Unaligned, !Immutable, !FromBytes);
1759
1760 assert_impls!(MaybeUninit<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, Unaligned, !IntoBytes);
1761 assert_impls!(MaybeUninit<NotZerocopy>: KnownLayout, TryFromBytes, FromZeros, FromBytes, !Immutable, !IntoBytes, !Unaligned);
1762 assert_impls!(MaybeUninit<UnsafeCell<()>>: KnownLayout, TryFromBytes, FromZeros, FromBytes, Unaligned, !Immutable, !IntoBytes);
1763
1764 assert_impls!(Wrapping<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
1765 // This test is important because it allows us to test our hand-rolled
1766 // implementation of `<Wrapping<T> as TryFromBytes>::is_bit_valid`.
1767 assert_impls!(Wrapping<bool>: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes);
1768 assert_impls!(Wrapping<NotZerocopy>: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1769 assert_impls!(Wrapping<UnsafeCell<()>>: KnownLayout, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned, !Immutable);
1770
1771 assert_impls!(Unalign<u8>: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
1772 // This test is important because it allows us to test our hand-rolled
1773 // implementation of `<Unalign<T> as TryFromBytes>::is_bit_valid`.
1774 assert_impls!(Unalign<bool>: KnownLayout, Immutable, TryFromBytes, FromZeros, IntoBytes, Unaligned, !FromBytes);
1775 assert_impls!(Unalign<NotZerocopy>: KnownLayout, Unaligned, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes);
1776
1777 assert_impls!(
1778 [u8]: KnownLayout,
1779 Immutable,
1780 TryFromBytes,
1781 FromZeros,
1782 FromBytes,
1783 IntoBytes,
1784 Unaligned
1785 );
1786 assert_impls!(
1787 [bool]: KnownLayout,
1788 Immutable,
1789 TryFromBytes,
1790 FromZeros,
1791 IntoBytes,
1792 Unaligned,
1793 !FromBytes
1794 );
1795 assert_impls!([NotZerocopy]: KnownLayout, !Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1796 assert_impls!(
1797 [u8; 0]: KnownLayout,
1798 Immutable,
1799 TryFromBytes,
1800 FromZeros,
1801 FromBytes,
1802 IntoBytes,
1803 Unaligned,
1804 );
1805 assert_impls!(
1806 [NotZerocopy; 0]: KnownLayout,
1807 !Immutable,
1808 !TryFromBytes,
1809 !FromZeros,
1810 !FromBytes,
1811 !IntoBytes,
1812 !Unaligned
1813 );
1814 assert_impls!(
1815 [u8; 1]: KnownLayout,
1816 Immutable,
1817 TryFromBytes,
1818 FromZeros,
1819 FromBytes,
1820 IntoBytes,
1821 Unaligned,
1822 );
1823 assert_impls!(
1824 [NotZerocopy; 1]: KnownLayout,
1825 !Immutable,
1826 !TryFromBytes,
1827 !FromZeros,
1828 !FromBytes,
1829 !IntoBytes,
1830 !Unaligned
1831 );
1832
1833 assert_impls!(*const NotZerocopy: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1834 assert_impls!(*mut NotZerocopy: KnownLayout, Immutable, TryFromBytes, FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1835 assert_impls!(*const [NotZerocopy]: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1836 assert_impls!(*mut [NotZerocopy]: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1837 assert_impls!(*const dyn Debug: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1838 assert_impls!(*mut dyn Debug: KnownLayout, Immutable, !TryFromBytes, !FromZeros, !FromBytes, !IntoBytes, !Unaligned);
1839
1840 #[cfg(feature = "simd")]
1841 {
1842 #[allow(unused_macros)]
1843 macro_rules! test_simd_arch_mod {
1844 ($arch:ident, $($typ:ident),*) => {
1845 {
1846 use core::arch::$arch::{$($typ),*};
1847 use crate::*;
1848 $( assert_impls!($typ: KnownLayout, Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, !Unaligned); )*
1849 }
1850 };
1851 }
1852 #[cfg(target_arch = "x86")]
1853 test_simd_arch_mod!(x86, __m128, __m128d, __m128i, __m256, __m256d, __m256i);
1854
1855 #[cfg(all(feature = "simd-nightly", target_arch = "x86"))]
1856 test_simd_arch_mod!(x86, __m512bh, __m512, __m512d, __m512i);
1857
1858 #[cfg(target_arch = "x86_64")]
1859 test_simd_arch_mod!(x86_64, __m128, __m128d, __m128i, __m256, __m256d, __m256i);
1860
1861 #[cfg(all(feature = "simd-nightly", target_arch = "x86_64"))]
1862 test_simd_arch_mod!(x86_64, __m512bh, __m512, __m512d, __m512i);
1863
1864 #[cfg(target_arch = "wasm32")]
1865 test_simd_arch_mod!(wasm32, v128);
1866
1867 #[cfg(all(feature = "simd-nightly", target_arch = "powerpc"))]
1868 test_simd_arch_mod!(
1869 powerpc,
1870 vector_bool_long,
1871 vector_double,
1872 vector_signed_long,
1873 vector_unsigned_long
1874 );
1875
1876 #[cfg(all(feature = "simd-nightly", target_arch = "powerpc64"))]
1877 test_simd_arch_mod!(
1878 powerpc64,
1879 vector_bool_long,
1880 vector_double,
1881 vector_signed_long,
1882 vector_unsigned_long
1883 );
1884 #[cfg(all(target_arch = "aarch64", zerocopy_aarch64_simd))]
1885 #[rustfmt::skip]
1886 test_simd_arch_mod!(
1887 aarch64, float32x2_t, float32x4_t, float64x1_t, float64x2_t, int8x8_t, int8x8x2_t,
1888 int8x8x3_t, int8x8x4_t, int8x16_t, int8x16x2_t, int8x16x3_t, int8x16x4_t, int16x4_t,
1889 int16x8_t, int32x2_t, int32x4_t, int64x1_t, int64x2_t, poly8x8_t, poly8x8x2_t, poly8x8x3_t,
1890 poly8x8x4_t, poly8x16_t, poly8x16x2_t, poly8x16x3_t, poly8x16x4_t, poly16x4_t, poly16x8_t,
1891 poly64x1_t, poly64x2_t, uint8x8_t, uint8x8x2_t, uint8x8x3_t, uint8x8x4_t, uint8x16_t,
1892 uint8x16x2_t, uint8x16x3_t, uint8x16x4_t, uint16x4_t, uint16x8_t, uint32x2_t, uint32x4_t,
1893 uint64x1_t, uint64x2_t
1894 );
1895 #[cfg(all(feature = "simd-nightly", target_arch = "arm"))]
1896 #[rustfmt::skip]
1897 test_simd_arch_mod!(arm, int8x4_t, uint8x4_t);
1898 }
1899 }
1900}