Skip to main content

zerocopy/
macros.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
10/// Safely transmutes a value of one type to a value of another type of the same
11/// size.
12///
13/// This macro behaves like an invocation of this function:
14///
15/// ```ignore
16/// const fn transmute<Src, Dst>(src: Src) -> Dst
17/// where
18///     Src: IntoBytes,
19///     Dst: FromBytes,
20///     size_of::<Src>() == size_of::<Dst>(),
21/// {
22/// # /*
23///     ...
24/// # */
25/// }
26/// ```
27///
28/// However, unlike a function, this macro can only be invoked when the types of
29/// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are
30/// inferred from the calling context; they cannot be explicitly specified in
31/// the macro invocation.
32///
33/// Note that the `Src` produced by the expression `$e` will *not* be dropped.
34/// Semantically, its bits will be copied into a new value of type `Dst`, the
35/// original `Src` will be forgotten, and the value of type `Dst` will be
36/// returned.
37///
38/// # `#![allow(shrink)]`
39///
40/// If `#![allow(shrink)]` is provided, `transmute!` additionally supports
41/// transmutations that shrink the size of the value; e.g.:
42///
43/// ```
44/// # use zerocopy::transmute;
45/// let u: u32 = transmute!(#![allow(shrink)] 0u64);
46/// assert_eq!(u, 0u32);
47/// ```
48///
49/// # Examples
50///
51/// ```
52/// # use zerocopy::transmute;
53/// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
54///
55/// let two_dimensional: [[u8; 4]; 2] = transmute!(one_dimensional);
56///
57/// assert_eq!(two_dimensional, [[0, 1, 2, 3], [4, 5, 6, 7]]);
58/// ```
59///
60/// # Use in `const` contexts
61///
62/// This macro can be invoked in `const` contexts.
63#[macro_export]
64macro_rules! transmute {
65    // NOTE: This must be a macro (rather than a function with trait bounds)
66    // because there's no way, in a generic context, to enforce that two types
67    // have the same size. `core::mem::transmute` uses compiler magic to enforce
68    // this so long as the types are concrete.
69    (#![allow(shrink)] $e:expr) => {{
70        let mut e = $e;
71        if false {
72            // This branch, though never taken, ensures that the type of `e` is
73            // `IntoBytes` and that the type of the  outer macro invocation
74            // expression is `FromBytes`.
75
76            fn transmute<Src, Dst>(src: Src) -> Dst
77            where
78                Src: $crate::IntoBytes,
79                Dst: $crate::FromBytes,
80            {
81                let _ = src;
82                loop {}
83            }
84            loop {}
85            #[allow(unreachable_code)]
86            transmute(e)
87        } else {
88            use $crate::util::macro_util::core_reexport::mem::ManuallyDrop;
89
90            // NOTE: `repr(packed)` is important! It ensures that the size of
91            // `Transmute` won't be rounded up to accommodate `Src`'s or `Dst`'s
92            // alignment, which would break the size comparison logic below.
93            //
94            // As an example of why this is problematic, consider `Src = [u8;
95            // 5]`, `Dst = u32`. The total size of `Transmute<Src, Dst>` would
96            // be 8, and so we would reject a `[u8; 5]` to `u32` transmute as
97            // being size-increasing, which it isn't.
98            #[repr(C, packed)]
99            union Transmute<Src, Dst> {
100                src: ManuallyDrop<Src>,
101                dst: ManuallyDrop<Dst>,
102            }
103
104            // SAFETY: `Transmute` is a `repr(C)` union whose `src` field has
105            // type `ManuallyDrop<Src>`. Thus, the `src` field starts at byte
106            // offset 0 within `Transmute` [1]. `ManuallyDrop<T>` has the same
107            // layout and bit validity as `T`, so it is sound to transmute `Src`
108            // to `Transmute`.
109            //
110            // [1] https://doc.rust-lang.org/1.85.0/reference/type-layout.html#reprc-unions
111            //
112            // [2] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html:
113            //
114            //   `ManuallyDrop<T>` is guaranteed to have the same layout and bit
115            //   validity as `T`
116            let u: Transmute<_, _> = unsafe {
117                // Clippy: We can't annotate the types; this macro is designed
118                // to infer the types from the calling context.
119                #[allow(clippy::missing_transmute_annotations)]
120                $crate::util::macro_util::core_reexport::mem::transmute(e)
121            };
122
123            if false {
124                // SAFETY: This code is never executed.
125                e = ManuallyDrop::into_inner(unsafe { u.src });
126                // Suppress the `unused_assignments` lint on the previous line.
127                let _ = e;
128                loop {}
129            } else {
130                // SAFETY: Per the safety comment on `let u` above, the `dst`
131                // field in `Transmute` starts at byte offset 0, and has the
132                // same layout and bit validity as `Dst`.
133                //
134                // Transmuting `Src` to `Transmute<Src, Dst>` above using
135                // `core::mem::transmute` ensures that `size_of::<Src>() ==
136                // size_of::<Transmute<Src, Dst>>()`. A `#[repr(C, packed)]`
137                // union has the maximum size of all of its fields [1], so this
138                // is equivalent to `size_of::<Src>() >= size_of::<Dst>()`.
139                //
140                // The outer `if`'s `false` branch ensures that `Src: IntoBytes`
141                // and `Dst: FromBytes`. This, combined with the size bound,
142                // ensures that this transmute is sound.
143                //
144                // [1] Per https://doc.rust-lang.org/1.85.0/reference/type-layout.html#reprc-unions:
145                //
146                //   The union will have a size of the maximum size of all of
147                //   its fields rounded to its alignment
148                let dst = unsafe { u.dst };
149                $crate::util::macro_util::must_use(ManuallyDrop::into_inner(dst))
150            }
151        }
152    }};
153    ($e:expr) => {{
154        let e = $e;
155        if false {
156            // This branch, though never taken, ensures that the type of `e` is
157            // `IntoBytes` and that the type of the  outer macro invocation
158            // expression is `FromBytes`.
159
160            fn transmute<Src, Dst>(src: Src) -> Dst
161            where
162                Src: $crate::IntoBytes,
163                Dst: $crate::FromBytes,
164            {
165                let _ = src;
166                loop {}
167            }
168            loop {}
169            #[allow(unreachable_code)]
170            transmute(e)
171        } else {
172            // SAFETY: `core::mem::transmute` ensures that the type of `e` and
173            // the type of this macro invocation expression have the same size.
174            // We know this transmute is safe thanks to the `IntoBytes` and
175            // `FromBytes` bounds enforced by the `false` branch.
176            let u = unsafe {
177                // Clippy: We can't annotate the types; this macro is designed
178                // to infer the types from the calling context.
179                #[allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
180                $crate::util::macro_util::core_reexport::mem::transmute(e)
181            };
182            $crate::util::macro_util::must_use(u)
183        }
184    }};
185}
186
187/// Safely transmutes a mutable or immutable reference of one type to an
188/// immutable reference of another type of the same size and compatible
189/// alignment.
190///
191/// This macro behaves like an invocation of this function:
192///
193/// ```ignore
194/// fn transmute_ref<'src, 'dst, Src, Dst>(src: &'src Src) -> &'dst Dst
195/// where
196///     'src: 'dst,
197///     Src: IntoBytes + Immutable + ?Sized,
198///     Dst: FromBytes + Immutable + ?Sized,
199///     align_of::<Src>() >= align_of::<Dst>(),
200///     size_compatible::<Src, Dst>(),
201/// {
202/// # /*
203///     ...
204/// # */
205/// }
206/// ```
207///
208/// The types `Src` and `Dst` are inferred from the calling context; they cannot
209/// be explicitly specified in the macro invocation.
210///
211/// # Size compatibility
212///
213/// `transmute_ref!` supports transmuting between `Sized` types, between unsized
214/// (i.e., `?Sized`) types, and from a `Sized` type to an unsized type. It
215/// supports any transmutation that preserves the number of bytes of the
216/// referent, even if doing so requires updating the metadata stored in an
217/// unsized "fat" reference:
218///
219/// ```
220/// # use zerocopy::transmute_ref;
221/// # use core::mem::size_of_val; // Not in the prelude on our MSRV
222/// let src: &[[u8; 2]] = &[[0, 1], [2, 3]][..];
223/// let dst: &[u8] = transmute_ref!(src);
224///
225/// assert_eq!(src.len(), 2);
226/// assert_eq!(dst.len(), 4);
227/// assert_eq!(dst, [0, 1, 2, 3]);
228/// assert_eq!(size_of_val(src), size_of_val(dst));
229/// ```
230///
231/// # Errors
232///
233/// Violations of the alignment and size compatibility checks are detected
234/// *after* the compiler performs monomorphization. This has two important
235/// consequences.
236///
237/// First, it means that generic code will *never* fail these conditions:
238///
239/// ```
240/// # use zerocopy::{transmute_ref, FromBytes, IntoBytes, Immutable};
241/// fn transmute_ref<Src, Dst>(src: &Src) -> &Dst
242/// where
243///     Src: IntoBytes + Immutable,
244///     Dst: FromBytes + Immutable,
245/// {
246///     transmute_ref!(src)
247/// }
248/// ```
249///
250/// Instead, failures will only be detected once generic code is instantiated
251/// with concrete types:
252///
253/// ```compile_fail,E0080
254/// # use zerocopy::{transmute_ref, FromBytes, IntoBytes, Immutable};
255/// #
256/// # fn transmute_ref<Src, Dst>(src: &Src) -> &Dst
257/// # where
258/// #     Src: IntoBytes + Immutable,
259/// #     Dst: FromBytes + Immutable,
260/// # {
261/// #     transmute_ref!(src)
262/// # }
263/// let src: &u16 = &0;
264/// let dst: &u8 = transmute_ref(src);
265/// ```
266///
267/// Second, the fact that violations are detected after monomorphization means
268/// that `cargo check` will usually not detect errors, even when types are
269/// concrete. Instead, `cargo build` must be used to detect such errors.
270///
271/// # Examples
272///
273/// Transmuting between `Sized` types:
274///
275/// ```
276/// # use zerocopy::transmute_ref;
277/// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
278///
279/// let two_dimensional: &[[u8; 4]; 2] = transmute_ref!(&one_dimensional);
280///
281/// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]);
282/// ```
283///
284/// Transmuting between unsized types:
285///
286/// ```
287/// # use {zerocopy::*, zerocopy_derive::*};
288/// # type u16 = zerocopy::byteorder::native_endian::U16;
289/// # type u32 = zerocopy::byteorder::native_endian::U32;
290/// #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)]
291/// #[repr(C)]
292/// struct SliceDst<T, U> {
293///     t: T,
294///     u: [U],
295/// }
296///
297/// type Src = SliceDst<u32, u16>;
298/// type Dst = SliceDst<u16, u8>;
299///
300/// let src = Src::ref_from_bytes(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
301/// let dst: &Dst = transmute_ref!(src);
302///
303/// assert_eq!(src.t.as_bytes(), [0, 1, 2, 3]);
304/// assert_eq!(src.u.len(), 2);
305/// assert_eq!(src.u.as_bytes(), [4, 5, 6, 7]);
306///
307/// assert_eq!(dst.t.as_bytes(), [0, 1]);
308/// assert_eq!(dst.u, [2, 3, 4, 5, 6, 7]);
309/// ```
310///
311/// # Use in `const` contexts
312///
313/// This macro can be invoked in `const` contexts only when `Src: Sized` and
314/// `Dst: Sized`.
315///
316/// # Code Generation
317///
318/// The below code generation benchmark exercises this routine on a
319/// destination type whose complex layout places complex requirements on the
320/// source:
321///
322/// - the source must begin an even memory address
323/// - the source has a minimum length of 4 bytes
324/// - the source has a total length divisible by 2
325///
326/// These conditions are all checked at compile time.
327#[doc = codegen_tabs!(format = "coco", bench = "transmute_ref")]
328#[macro_export]
329macro_rules! transmute_ref {
330    ($e:expr) => {{
331        // NOTE: This must be a macro (rather than a function with trait bounds)
332        // because there's no way, in a generic context, to enforce that two
333        // types have the same size or alignment.
334
335        // Ensure that the source type is a reference or a mutable reference
336        // (note that mutable references are implicitly reborrowed here).
337        let e: &_ = $e;
338
339        #[allow(unused, clippy::diverging_sub_expression)]
340        if false {
341            // This branch, though never taken, ensures that the type of `e` is
342            // `&T` where `T: IntoBytes + Immutable`, and that the type of this
343            // macro expression is `&U` where `U: FromBytes + Immutable`.
344
345            struct AssertSrcIsIntoBytes<'a, T: ?::core::marker::Sized + $crate::IntoBytes>(&'a T);
346            struct AssertSrcIsImmutable<'a, T: ?::core::marker::Sized + $crate::Immutable>(&'a T);
347            struct AssertDstIsFromBytes<'a, U: ?::core::marker::Sized + $crate::FromBytes>(&'a U);
348            struct AssertDstIsImmutable<'a, T: ?::core::marker::Sized + $crate::Immutable>(&'a T);
349
350            let _ = AssertSrcIsIntoBytes(e);
351            let _ = AssertSrcIsImmutable(e);
352
353            if true {
354                #[allow(unused, unreachable_code)]
355                let u = AssertDstIsFromBytes(loop {});
356                u.0
357            } else {
358                #[allow(unused, unreachable_code)]
359                let u = AssertDstIsImmutable(loop {});
360                u.0
361            }
362        } else {
363            use $crate::util::macro_util::TransmuteRefDst;
364            let t = $crate::util::macro_util::Wrap::new(e);
365
366            if false {
367                // This branch exists solely to force the compiler to infer the
368                // type of `Dst` *before* it attempts to resolve the method call
369                // to `transmute_ref` in the `else` branch.
370                //
371                // Without this, if `Src` is `Sized` but `Dst` is `!Sized`, the
372                // compiler will eagerly select the inherent impl of
373                // `transmute_ref` (which requires `Dst: Sized`) because inherent
374                // methods take priority over trait methods. It does this before
375                // it realizes `Dst` is `!Sized`, leading to a compile error when
376                // it checks the bounds later.
377                //
378                // By calling this helper (which returns `&Dst`), we force `Dst`
379                // to be fully resolved. By the time it gets to the `else`
380                // branch, the compiler knows `Dst` is `!Sized`, properly
381                // disqualifies the inherent method, and falls back to the trait
382                // implementation.
383                t.transmute_ref_inference_helper()
384            } else {
385                // SAFETY: The outer `if false` branch ensures that:
386                // - `Src: IntoBytes + Immutable`
387                // - `Dst: FromBytes + Immutable`
388                unsafe {
389                    t.transmute_ref()
390                }
391            }
392        }
393    }}
394}
395
396/// Safely transmutes a mutable reference of one type to a mutable reference of
397/// another type of the same size and compatible alignment.
398///
399/// This macro behaves like an invocation of this function:
400///
401/// ```ignore
402/// const fn transmute_mut<'src, 'dst, Src, Dst>(src: &'src mut Src) -> &'dst mut Dst
403/// where
404///     'src: 'dst,
405///     Src: FromBytes + IntoBytes + ?Sized,
406///     Dst: FromBytes + IntoBytes + ?Sized,
407///     align_of::<Src>() >= align_of::<Dst>(),
408///     size_compatible::<Src, Dst>(),
409/// {
410/// # /*
411///     ...
412/// # */
413/// }
414/// ```
415///
416/// The types `Src` and `Dst` are inferred from the calling context; they cannot
417/// be explicitly specified in the macro invocation.
418///
419/// # Size compatibility
420///
421/// `transmute_mut!` supports transmuting between `Sized` types, between unsized
422/// (i.e., `?Sized`) types, and from a `Sized` type to an unsized type. It
423/// supports any transmutation that preserves the number of bytes of the
424/// referent, even if doing so requires updating the metadata stored in an
425/// unsized "fat" reference:
426///
427/// ```
428/// # use zerocopy::transmute_mut;
429/// # use core::mem::size_of_val; // Not in the prelude on our MSRV
430/// let src: &mut [[u8; 2]] = &mut [[0, 1], [2, 3]][..];
431/// let dst: &mut [u8] = transmute_mut!(src);
432///
433/// assert_eq!(dst.len(), 4);
434/// assert_eq!(dst, [0, 1, 2, 3]);
435/// let dst_size = size_of_val(dst);
436/// assert_eq!(src.len(), 2);
437/// assert_eq!(size_of_val(src), dst_size);
438/// ```
439///
440/// # Errors
441///
442/// Violations of the alignment and size compatibility checks are detected
443/// *after* the compiler performs monomorphization. This has two important
444/// consequences.
445///
446/// First, it means that generic code will *never* fail these conditions:
447///
448/// ```
449/// # use zerocopy::{transmute_mut, FromBytes, IntoBytes, Immutable};
450/// fn transmute_mut<Src, Dst>(src: &mut Src) -> &mut Dst
451/// where
452///     Src: FromBytes + IntoBytes,
453///     Dst: FromBytes + IntoBytes,
454/// {
455///     transmute_mut!(src)
456/// }
457/// ```
458///
459/// Instead, failures will only be detected once generic code is instantiated
460/// with concrete types:
461///
462/// ```compile_fail,E0080
463/// # use zerocopy::{transmute_mut, FromBytes, IntoBytes, Immutable};
464/// #
465/// # fn transmute_mut<Src, Dst>(src: &mut Src) -> &mut Dst
466/// # where
467/// #     Src: FromBytes + IntoBytes,
468/// #     Dst: FromBytes + IntoBytes,
469/// # {
470/// #     transmute_mut!(src)
471/// # }
472/// let src: &mut u16 = &mut 0;
473/// let dst: &mut u8 = transmute_mut(src);
474/// ```
475///
476/// Second, the fact that violations are detected after monomorphization means
477/// that `cargo check` will usually not detect errors, even when types are
478/// concrete. Instead, `cargo build` must be used to detect such errors.
479///
480///
481/// # Examples
482///
483/// Transmuting between `Sized` types:
484///
485/// ```
486/// # use zerocopy::transmute_mut;
487/// let mut one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
488///
489/// let two_dimensional: &mut [[u8; 4]; 2] = transmute_mut!(&mut one_dimensional);
490///
491/// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]);
492///
493/// two_dimensional.reverse();
494///
495/// assert_eq!(one_dimensional, [4, 5, 6, 7, 0, 1, 2, 3]);
496/// ```
497///
498/// Transmuting between unsized types:
499///
500/// ```
501/// # use {zerocopy::*, zerocopy_derive::*};
502/// # type u16 = zerocopy::byteorder::native_endian::U16;
503/// # type u32 = zerocopy::byteorder::native_endian::U32;
504/// #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)]
505/// #[repr(C)]
506/// struct SliceDst<T, U> {
507///     t: T,
508///     u: [U],
509/// }
510///
511/// type Src = SliceDst<u32, u16>;
512/// type Dst = SliceDst<u16, u8>;
513///
514/// let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7];
515/// let src = Src::mut_from_bytes(&mut bytes[..]).unwrap();
516/// let dst: &mut Dst = transmute_mut!(src);
517///
518/// assert_eq!(dst.t.as_bytes(), [0, 1]);
519/// assert_eq!(dst.u, [2, 3, 4, 5, 6, 7]);
520///
521/// assert_eq!(src.t.as_bytes(), [0, 1, 2, 3]);
522/// assert_eq!(src.u.len(), 2);
523/// assert_eq!(src.u.as_bytes(), [4, 5, 6, 7]);
524///
525/// ```
526#[macro_export]
527macro_rules! transmute_mut {
528    ($e:expr) => {{
529        // NOTE: This must be a macro (rather than a function with trait bounds)
530        // because, for backwards-compatibility on v0.8.x, we use the autoref
531        // specialization trick to dispatch to different `transmute_mut`
532        // implementations: one which doesn't require `Src: KnownLayout + Dst:
533        // KnownLayout` when `Src: Sized + Dst: Sized`, and one which requires
534        // `KnownLayout` bounds otherwise.
535
536        // Ensure that the source type is a mutable reference.
537        let e: &mut _ = $e;
538
539        #[allow(unused)]
540        use $crate::util::macro_util::TransmuteMutDst as _;
541        let t = $crate::util::macro_util::Wrap::new(e);
542        if false {
543            // This branch exists solely to force the compiler to infer the type
544            // of `Dst` *before* it attempts to resolve the method call to
545            // `transmute_mut` in the `else` branch.
546            //
547            // Without this, if `Src` is `Sized` but `Dst` is `!Sized`, the
548            // compiler will eagerly select the inherent impl of `transmute_mut`
549            // (which requires `Dst: Sized`) because inherent methods take
550            // priority over trait methods. It does this before it realizes
551            // `Dst` is `!Sized`, leading to a compile error when it checks the
552            // bounds later.
553            //
554            // By calling this helper (which returns `&mut Dst`), we force `Dst`
555            // to be fully resolved. By the time it gets to the `else` branch,
556            // the compiler knows `Dst` is `!Sized`, properly disqualifies the
557            // inherent method, and falls back to the trait implementation.
558            t.transmute_mut_inference_helper()
559        } else {
560            t.transmute_mut()
561        }
562    }}
563}
564
565/// Conditionally transmutes a value of one type to a value of another type of
566/// the same size.
567///
568/// This macro behaves like an invocation of this function:
569///
570/// ```ignore
571/// fn try_transmute<Src, Dst>(src: Src) -> Result<Dst, ValidityError<Src, Dst>>
572/// where
573///     Src: IntoBytes,
574///     Dst: TryFromBytes,
575///     size_of::<Src>() == size_of::<Dst>(),
576/// {
577/// # /*
578///     ...
579/// # */
580/// }
581/// ```
582///
583/// However, unlike a function, this macro can only be invoked when the types of
584/// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are
585/// inferred from the calling context; they cannot be explicitly specified in
586/// the macro invocation.
587///
588/// Note that the `Src` produced by the expression `$e` will *not* be dropped.
589/// Semantically, its bits will be copied into a new value of type `Dst`, the
590/// original `Src` will be forgotten, and the value of type `Dst` will be
591/// returned.
592///
593/// # Examples
594///
595/// ```
596/// # use zerocopy::*;
597/// // 0u8 → bool = false
598/// assert_eq!(try_transmute!(0u8), Ok(false));
599///
600/// // 1u8 → bool = true
601///  assert_eq!(try_transmute!(1u8), Ok(true));
602///
603/// // 2u8 → bool = error
604/// assert!(matches!(
605///     try_transmute!(2u8),
606///     Result::<bool, _>::Err(ValidityError { .. })
607/// ));
608/// ```
609#[macro_export]
610macro_rules! try_transmute {
611    ($e:expr) => {{
612        // NOTE: This must be a macro (rather than a function with trait bounds)
613        // because there's no way, in a generic context, to enforce that two
614        // types have the same size. `core::mem::transmute` uses compiler magic
615        // to enforce this so long as the types are concrete.
616
617        let e = $e;
618        if false {
619            // Check that the sizes of the source and destination types are
620            // equal.
621
622            // SAFETY: This code is never executed.
623            Ok(unsafe {
624                // Clippy: We can't annotate the types; this macro is designed
625                // to infer the types from the calling context.
626                #[allow(clippy::missing_transmute_annotations)]
627                $crate::util::macro_util::core_reexport::mem::transmute(e)
628            })
629        } else {
630            $crate::util::macro_util::try_transmute::<_, _>(e)
631        }
632    }}
633}
634
635/// Conditionally transmutes a mutable or immutable reference of one type to an
636/// immutable reference of another type of the same size and compatible
637/// alignment.
638///
639/// *Note that while the **value** of the referent is checked for validity at
640/// runtime, the **size** and **alignment** are checked at compile time. For
641/// conversions which are fallible with respect to size and alignment, see the
642/// methods on [`TryFromBytes`].*
643///
644/// This macro behaves like an invocation of this function:
645///
646/// ```ignore
647/// fn try_transmute_ref<Src, Dst>(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>>
648/// where
649///     Src: IntoBytes + Immutable + ?Sized,
650///     Dst: TryFromBytes + Immutable + ?Sized,
651///     align_of::<Src>() >= align_of::<Dst>(),
652///     size_compatible::<Src, Dst>(),
653/// {
654/// # /*
655///     ...
656/// # */
657/// }
658/// ```
659///
660/// The types `Src` and `Dst` are inferred from the calling context; they cannot
661/// be explicitly specified in the macro invocation.
662///
663/// [`TryFromBytes`]: crate::TryFromBytes
664///
665/// # Size compatibility
666///
667/// `try_transmute_ref!` supports transmuting between `Sized` types, between
668/// unsized (i.e., `?Sized`) types, and from a `Sized` type to an unsized type.
669/// It supports any transmutation that preserves the number of bytes of the
670/// referent, even if doing so requires updating the metadata stored in an
671/// unsized "fat" reference:
672///
673/// ```
674/// # use zerocopy::try_transmute_ref;
675/// # use core::mem::size_of_val; // Not in the prelude on our MSRV
676/// let src: &[[u8; 2]] = &[[0, 1], [2, 3]][..];
677/// let dst: &[u8] = try_transmute_ref!(src).unwrap();
678///
679/// assert_eq!(src.len(), 2);
680/// assert_eq!(dst.len(), 4);
681/// assert_eq!(dst, [0, 1, 2, 3]);
682/// assert_eq!(size_of_val(src), size_of_val(dst));
683/// ```
684///
685/// # Examples
686///
687/// Transmuting between `Sized` types:
688///
689/// ```
690/// # use zerocopy::*;
691/// // 0u8 → bool = false
692/// assert_eq!(try_transmute_ref!(&0u8), Ok(&false));
693///
694/// // 1u8 → bool = true
695///  assert_eq!(try_transmute_ref!(&1u8), Ok(&true));
696///
697/// // 2u8 → bool = error
698/// assert!(matches!(
699///     try_transmute_ref!(&2u8),
700///     Result::<&bool, _>::Err(ValidityError { .. })
701/// ));
702/// ```
703///
704/// Transmuting between unsized types:
705///
706/// ```
707/// # use {zerocopy::*, zerocopy_derive::*};
708/// # type u16 = zerocopy::byteorder::native_endian::U16;
709/// # type u32 = zerocopy::byteorder::native_endian::U32;
710/// #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)]
711/// #[repr(C)]
712/// struct SliceDst<T, U> {
713///     t: T,
714///     u: [U],
715/// }
716///
717/// type Src = SliceDst<u32, u16>;
718/// type Dst = SliceDst<u16, bool>;
719///
720/// let src = Src::ref_from_bytes(&[0, 1, 0, 1, 0, 1, 0, 1]).unwrap();
721/// let dst: &Dst = try_transmute_ref!(src).unwrap();
722///
723/// assert_eq!(src.t.as_bytes(), [0, 1, 0, 1]);
724/// assert_eq!(src.u.len(), 2);
725/// assert_eq!(src.u.as_bytes(), [0, 1, 0, 1]);
726///
727/// assert_eq!(dst.t.as_bytes(), [0, 1]);
728/// assert_eq!(dst.u, [false, true, false, true, false, true]);
729/// ```
730///
731/// # Code Generation
732///
733/// The below code generation benchmark exercises this routine on a
734/// destination type whose complex layout places complex requirements on the
735/// source:
736///
737/// - the source must begin an even memory address
738/// - the source has a minimum length of 4 bytes
739/// - the source has a total length divisible by 2
740/// - the source begins with the bytes `0xC0C0`
741///
742/// All except the final condition are checked at compile time.
743#[doc = codegen_tabs!(format = "coco", bench = "try_transmute_ref")]
744#[macro_export]
745macro_rules! try_transmute_ref {
746    ($e:expr) => {{
747        // Ensure that the source type is a reference or a mutable reference
748        // (note that mutable references are implicitly reborrowed here).
749        let e: &_ = $e;
750
751        #[allow(unused_imports)]
752        use $crate::util::macro_util::TryTransmuteRefDst as _;
753        let t = $crate::util::macro_util::Wrap::new(e);
754        if false {
755            // This branch exists solely to force the compiler to infer the type
756            // of `Dst` *before* it attempts to resolve the method call to
757            // `try_transmute_ref` in the `else` branch.
758            //
759            // Without this, if `Src` is `Sized` but `Dst` is `!Sized`, the
760            // compiler will eagerly select the inherent impl of
761            // `try_transmute_ref` (which requires `Dst: Sized`) because
762            // inherent methods take priority over trait methods. It does this
763            // before it realizes `Dst` is `!Sized`, leading to a compile error
764            // when it checks the bounds later.
765            //
766            // By calling this helper (which returns `&Dst`), we force `Dst`
767            // to be fully resolved. By the time it gets to the `else`
768            // branch, the compiler knows `Dst` is `!Sized`, properly
769            // disqualifies the inherent method, and falls back to the trait
770            // implementation.
771            Ok(t.transmute_ref_inference_helper())
772        } else {
773            t.try_transmute_ref()
774        }
775    }}
776}
777
778/// Conditionally transmutes a mutable reference of one type to a mutable
779/// reference of another type of the same size and compatible alignment.
780///
781/// *Note that while the **value** of the referent is checked for validity at
782/// runtime, the **size** and **alignment** are checked at compile time. For
783/// conversions which are fallible with respect to size and alignment, see the
784/// methods on [`TryFromBytes`].*
785///
786/// This macro behaves like an invocation of this function:
787///
788/// ```ignore
789/// fn try_transmute_mut<Src, Dst>(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>>
790/// where
791///     Src: FromBytes + IntoBytes + ?Sized,
792///     Dst: TryFromBytes + IntoBytes + ?Sized,
793///     align_of::<Src>() >= align_of::<Dst>(),
794///     size_compatible::<Src, Dst>(),
795/// {
796/// # /*
797///     ...
798/// # */
799/// }
800/// ```
801///
802/// The types `Src` and `Dst` are inferred from the calling context; they cannot
803/// be explicitly specified in the macro invocation.
804///
805/// [`TryFromBytes`]: crate::TryFromBytes
806///
807/// # Size compatibility
808///
809/// `try_transmute_mut!` supports transmuting between `Sized` types, between
810/// unsized (i.e., `?Sized`) types, and from a `Sized` type to an unsized type.
811/// It supports any transmutation that preserves the number of bytes of the
812/// referent, even if doing so requires updating the metadata stored in an
813/// unsized "fat" reference:
814///
815/// ```
816/// # use zerocopy::try_transmute_mut;
817/// # use core::mem::size_of_val; // Not in the prelude on our MSRV
818/// let src: &mut [[u8; 2]] = &mut [[0, 1], [2, 3]][..];
819/// let dst: &mut [u8] = try_transmute_mut!(src).unwrap();
820///
821/// assert_eq!(dst.len(), 4);
822/// assert_eq!(dst, [0, 1, 2, 3]);
823/// let dst_size = size_of_val(dst);
824/// assert_eq!(src.len(), 2);
825/// assert_eq!(size_of_val(src), dst_size);
826/// ```
827///
828/// # Examples
829///
830/// Transmuting between `Sized` types:
831///
832/// ```
833/// # use zerocopy::*;
834/// // 0u8 → bool = false
835/// let src = &mut 0u8;
836/// assert_eq!(try_transmute_mut!(src), Ok(&mut false));
837///
838/// // 1u8 → bool = true
839/// let src = &mut 1u8;
840///  assert_eq!(try_transmute_mut!(src), Ok(&mut true));
841///
842/// // 2u8 → bool = error
843/// let src = &mut 2u8;
844/// assert!(matches!(
845///     try_transmute_mut!(src),
846///     Result::<&mut bool, _>::Err(ValidityError { .. })
847/// ));
848/// ```
849///
850/// Transmuting between unsized types:
851///
852/// ```
853/// # use {zerocopy::*, zerocopy_derive::*};
854/// # type u16 = zerocopy::byteorder::native_endian::U16;
855/// # type u32 = zerocopy::byteorder::native_endian::U32;
856/// #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)]
857/// #[repr(C)]
858/// struct SliceDst<T, U> {
859///     t: T,
860///     u: [U],
861/// }
862///
863/// type Src = SliceDst<u32, u16>;
864/// type Dst = SliceDst<u16, bool>;
865///
866/// let mut bytes = [0, 1, 0, 1, 0, 1, 0, 1];
867/// let src = Src::mut_from_bytes(&mut bytes).unwrap();
868///
869/// assert_eq!(src.t.as_bytes(), [0, 1, 0, 1]);
870/// assert_eq!(src.u.len(), 2);
871/// assert_eq!(src.u.as_bytes(), [0, 1, 0, 1]);
872///
873/// let dst: &Dst = try_transmute_mut!(src).unwrap();
874///
875/// assert_eq!(dst.t.as_bytes(), [0, 1]);
876/// assert_eq!(dst.u, [false, true, false, true, false, true]);
877/// ```
878#[macro_export]
879macro_rules! try_transmute_mut {
880    ($e:expr) => {{
881        // Ensure that the source type is a mutable reference.
882        let e: &mut _ = $e;
883
884        #[allow(unused_imports)]
885        use $crate::util::macro_util::TryTransmuteMutDst as _;
886        let t = $crate::util::macro_util::Wrap::new(e);
887        if false {
888            // This branch exists solely to force the compiler to infer the type
889            // of `Dst` *before* it attempts to resolve the method call to
890            // `try_transmute_mut` in the `else` branch.
891            //
892            // Without this, if `Src` is `Sized` but `Dst` is `!Sized`, the
893            // compiler will eagerly select the inherent impl of
894            // `try_transmute_mut` (which requires `Dst: Sized`) because
895            // inherent methods take priority over trait methods. It does this
896            // before it realizes `Dst` is `!Sized`, leading to a compile error
897            // when it checks the bounds later.
898            //
899            // By calling this helper (which returns `&Dst`), we force `Dst`
900            // to be fully resolved. By the time it gets to the `else`
901            // branch, the compiler knows `Dst` is `!Sized`, properly
902            // disqualifies the inherent method, and falls back to the trait
903            // implementation.
904            Ok(t.transmute_mut_inference_helper())
905        } else {
906            t.try_transmute_mut()
907        }
908    }}
909}
910
911/// Includes a file and safely transmutes it to a value of an arbitrary type.
912///
913/// The file will be included as a byte array, `[u8; N]`, which will be
914/// transmuted to another type, `T`. `T` is inferred from the calling context,
915/// and must implement [`FromBytes`].
916///
917/// The file is located relative to the current file (similarly to how modules
918/// are found). The provided path is interpreted in a platform-specific way at
919/// compile time. So, for instance, an invocation with a Windows path containing
920/// backslashes `\` would not compile correctly on Unix.
921///
922/// `include_value!` is ignorant of byte order. For byte order-aware types, see
923/// the [`byteorder`] module.
924///
925/// [`FromBytes`]: crate::FromBytes
926/// [`byteorder`]: crate::byteorder
927///
928/// # Examples
929///
930/// Assume there are two files in the same directory with the following
931/// contents:
932///
933/// File `data` (no trailing newline):
934///
935/// ```text
936/// abcd
937/// ```
938///
939/// File `main.rs`:
940///
941/// ```rust
942/// use zerocopy::include_value;
943/// # macro_rules! include_value {
944/// # ($file:expr) => { zerocopy::include_value!(concat!("../testdata/include_value/", $file)) };
945/// # }
946///
947/// fn main() {
948///     let as_u32: u32 = include_value!("data");
949///     assert_eq!(as_u32, u32::from_ne_bytes([b'a', b'b', b'c', b'd']));
950///     let as_i32: i32 = include_value!("data");
951///     assert_eq!(as_i32, i32::from_ne_bytes([b'a', b'b', b'c', b'd']));
952/// }
953/// ```
954///
955/// # Use in `const` contexts
956///
957/// This macro can be invoked in `const` contexts.
958#[doc(alias("include_bytes", "include_data", "include_type"))]
959#[macro_export]
960macro_rules! include_value {
961    ($file:expr $(,)?) => {
962        $crate::transmute!(*::core::include_bytes!($file))
963    };
964}
965
966#[doc(hidden)]
967#[macro_export]
968macro_rules! cryptocorrosion_derive_traits {
969    (
970        #[repr($repr:ident)]
971        $(#[$attr:meta])*
972        $vis:vis struct $name:ident $(<$($tyvar:ident),*>)?
973        $(
974            (
975                $($tuple_field_vis:vis $tuple_field_ty:ty),*
976            );
977        )?
978
979        $(
980            {
981                $($field_vis:vis $field_name:ident: $field_ty:ty,)*
982            }
983        )?
984    ) => {
985        $crate::cryptocorrosion_derive_traits!(@assert_allowed_struct_repr #[repr($repr)]);
986
987        $(#[$attr])*
988        #[repr($repr)]
989        $vis struct $name $(<$($tyvar),*>)?
990        $(
991            (
992                $($tuple_field_vis $tuple_field_ty),*
993            );
994        )?
995
996        $(
997            {
998                $($field_vis $field_name: $field_ty,)*
999            }
1000        )?
1001
1002        // SAFETY: See inline.
1003        unsafe impl $(<$($tyvar),*>)? $crate::TryFromBytes for $name$(<$($tyvar),*>)?
1004        where
1005            $(
1006                $($tuple_field_ty: $crate::FromBytes,)*
1007            )?
1008
1009            $(
1010                $($field_ty: $crate::FromBytes,)*
1011            )?
1012        {
1013            #[inline(always)]
1014            fn is_bit_valid<A>(_: $crate::Maybe<'_, Self, A>) -> bool
1015            where
1016                A: $crate::invariant::Alignment,
1017            {
1018                // SAFETY: This macro only accepts `#[repr(C)]` and
1019                // `#[repr(transparent)]` structs, and this `impl` block
1020                // requires all field types to be `FromBytes`. Thus, all
1021                // initialized byte sequences constitutes valid instances of
1022                // `Self`.
1023                true
1024            }
1025
1026            fn only_derive_is_allowed_to_implement_this_trait() {}
1027        }
1028
1029        // SAFETY: This macro only accepts `#[repr(C)]` and
1030        // `#[repr(transparent)]` structs, and this `impl` block requires all
1031        // field types to be `FromBytes`, which is a sub-trait of `FromZeros`.
1032        unsafe impl $(<$($tyvar),*>)? $crate::FromZeros for $name$(<$($tyvar),*>)?
1033        where
1034            $(
1035                $($tuple_field_ty: $crate::FromBytes,)*
1036            )?
1037
1038            $(
1039                $($field_ty: $crate::FromBytes,)*
1040            )?
1041        {
1042            fn only_derive_is_allowed_to_implement_this_trait() {}
1043        }
1044
1045        // SAFETY: This macro only accepts `#[repr(C)]` and
1046        // `#[repr(transparent)]` structs, and this `impl` block requires all
1047        // field types to be `FromBytes`.
1048        unsafe impl $(<$($tyvar),*>)? $crate::FromBytes for $name$(<$($tyvar),*>)?
1049        where
1050            $(
1051                $($tuple_field_ty: $crate::FromBytes,)*
1052            )?
1053
1054            $(
1055                $($field_ty: $crate::FromBytes,)*
1056            )?
1057        {
1058            fn only_derive_is_allowed_to_implement_this_trait() {}
1059        }
1060
1061        // SAFETY: This macro only accepts `#[repr(C)]` and
1062        // `#[repr(transparent)]` structs, this `impl` block requires all field
1063        // types to be `IntoBytes`, and a padding check is used to ensures that
1064        // there are no padding bytes.
1065        unsafe impl $(<$($tyvar),*>)? $crate::IntoBytes for $name$(<$($tyvar),*>)?
1066        where
1067            $(
1068                $($tuple_field_ty: $crate::IntoBytes,)*
1069            )?
1070
1071            $(
1072                $($field_ty: $crate::IntoBytes,)*
1073            )?
1074
1075            (): $crate::util::macro_util::PaddingFree<
1076                Self,
1077                {
1078                    $crate::cryptocorrosion_derive_traits!(
1079                        @struct_padding_check #[repr($repr)]
1080                        $(($($tuple_field_ty),*))?
1081                        $({$($field_ty),*})?
1082                    )
1083                },
1084            >,
1085        {
1086            fn only_derive_is_allowed_to_implement_this_trait() {}
1087        }
1088
1089        // SAFETY: This macro only accepts `#[repr(C)]` and
1090        // `#[repr(transparent)]` structs, and this `impl` block requires all
1091        // field types to be `Immutable`.
1092        unsafe impl $(<$($tyvar),*>)? $crate::Immutable for $name$(<$($tyvar),*>)?
1093        where
1094            $(
1095                $($tuple_field_ty: $crate::Immutable,)*
1096            )?
1097
1098            $(
1099                $($field_ty: $crate::Immutable,)*
1100            )?
1101        {
1102            fn only_derive_is_allowed_to_implement_this_trait() {}
1103        }
1104    };
1105    (@assert_allowed_struct_repr #[repr(transparent)]) => {};
1106    (@assert_allowed_struct_repr #[repr(C)]) => {};
1107    (@assert_allowed_struct_repr #[$_attr:meta]) => {
1108        compile_error!("repr must be `#[repr(transparent)]` or `#[repr(C)]`");
1109    };
1110    (
1111        @struct_padding_check #[repr(transparent)]
1112        $(($($tuple_field_ty:ty),*))?
1113        $({$($field_ty:ty),*})?
1114    ) => {
1115        // SAFETY: `#[repr(transparent)]` structs cannot have the same layout as
1116        // their single non-zero-sized field, and so cannot have any padding
1117        // outside of that field.
1118        0
1119    };
1120    (
1121        @struct_padding_check #[repr(C)]
1122        $(($($tuple_field_ty:ty),*))?
1123        $({$($field_ty:ty),*})?
1124    ) => {
1125        $crate::struct_padding!(
1126            Self,
1127            None,
1128            None,
1129            [
1130                $($($tuple_field_ty),*)?
1131                $($($field_ty),*)?
1132            ]
1133        )
1134    };
1135    (
1136        #[repr(C)]
1137        $(#[$attr:meta])*
1138        $vis:vis union $name:ident {
1139            $(
1140                $field_name:ident: $field_ty:ty,
1141            )*
1142        }
1143    ) => {
1144        $(#[$attr])*
1145        #[repr(C)]
1146        $vis union $name {
1147            $(
1148                $field_name: $field_ty,
1149            )*
1150        }
1151
1152        // SAFETY: See inline.
1153        unsafe impl $crate::TryFromBytes for $name
1154        where
1155            $(
1156                $field_ty: $crate::FromBytes,
1157            )*
1158        {
1159            #[inline(always)]
1160            fn is_bit_valid<A>(_: $crate::Maybe<'_, Self, A>) -> bool
1161            where
1162                A: $crate::invariant::Alignment,
1163            {
1164                // SAFETY: This macro only accepts `#[repr(C)]` unions, and this
1165                // `impl` block requires all field types to be `FromBytes`.
1166                // Thus, all initialized byte sequences constitutes valid
1167                // instances of `Self`.
1168                true
1169            }
1170
1171            fn only_derive_is_allowed_to_implement_this_trait() {}
1172        }
1173
1174        // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl`
1175        // block requires all field types to be `FromBytes`, which is a
1176        // sub-trait of `FromZeros`.
1177        unsafe impl $crate::FromZeros for $name
1178        where
1179            $(
1180                $field_ty: $crate::FromBytes,
1181            )*
1182        {
1183            fn only_derive_is_allowed_to_implement_this_trait() {}
1184        }
1185
1186        // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl`
1187        // block requires all field types to be `FromBytes`.
1188        unsafe impl $crate::FromBytes for $name
1189        where
1190            $(
1191                $field_ty: $crate::FromBytes,
1192            )*
1193        {
1194            fn only_derive_is_allowed_to_implement_this_trait() {}
1195        }
1196
1197        // SAFETY: This macro only accepts `#[repr(C)]` unions, this `impl`
1198        // block requires all field types to be `IntoBytes`, and a padding check
1199        // is used to ensures that there are no padding bytes before or after
1200        // any field.
1201        unsafe impl $crate::IntoBytes for $name
1202        where
1203            $(
1204                $field_ty: $crate::IntoBytes,
1205            )*
1206            (): $crate::util::macro_util::PaddingFree<
1207                Self,
1208                {
1209                    $crate::union_padding!(
1210                        Self,
1211                        None::<usize>,
1212                        None::<usize>,
1213                        [$($field_ty),*]
1214                    )
1215                },
1216            >,
1217        {
1218            fn only_derive_is_allowed_to_implement_this_trait() {}
1219        }
1220
1221        // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl`
1222        // block requires all field types to be `Immutable`.
1223        unsafe impl $crate::Immutable for $name
1224        where
1225            $(
1226                $field_ty: $crate::Immutable,
1227            )*
1228        {
1229            fn only_derive_is_allowed_to_implement_this_trait() {}
1230        }
1231    };
1232}
1233
1234#[cfg(test)]
1235mod tests {
1236    use crate::{
1237        byteorder::native_endian::{U16, U32},
1238        util::testutil::*,
1239        *,
1240    };
1241
1242    #[derive(KnownLayout, Immutable, FromBytes, IntoBytes, PartialEq, Debug)]
1243    #[repr(C)]
1244    struct SliceDst<T, U> {
1245        a: T,
1246        b: [U],
1247    }
1248
1249    #[test]
1250    fn test_transmute() {
1251        // Test that memory is transmuted as expected.
1252        let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
1253        let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
1254        let x: [[u8; 2]; 4] = transmute!(array_of_u8s);
1255        assert_eq!(x, array_of_arrays);
1256        let x: [u8; 8] = transmute!(array_of_arrays);
1257        assert_eq!(x, array_of_u8s);
1258
1259        // Test that memory is transmuted as expected when shrinking.
1260        let x: [[u8; 2]; 3] = transmute!(#![allow(shrink)] array_of_u8s);
1261        assert_eq!(x, [[0u8, 1], [2, 3], [4, 5]]);
1262
1263        // Test that the source expression's value is forgotten rather than
1264        // dropped.
1265        #[derive(IntoBytes)]
1266        #[repr(transparent)]
1267        struct PanicOnDrop(());
1268        impl Drop for PanicOnDrop {
1269            fn drop(&mut self) {
1270                panic!("PanicOnDrop::drop");
1271            }
1272        }
1273        #[allow(clippy::let_unit_value)]
1274        let _: () = transmute!(PanicOnDrop(()));
1275        #[allow(clippy::let_unit_value)]
1276        let _: () = transmute!(#![allow(shrink)] PanicOnDrop(()));
1277
1278        // Test that `transmute!` is legal in a const context.
1279        const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7];
1280        const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]];
1281        const X: [[u8; 2]; 4] = transmute!(ARRAY_OF_U8S);
1282        assert_eq!(X, ARRAY_OF_ARRAYS);
1283        const X_SHRINK: [[u8; 2]; 3] = transmute!(#![allow(shrink)] ARRAY_OF_U8S);
1284        assert_eq!(X_SHRINK, [[0u8, 1], [2, 3], [4, 5]]);
1285
1286        // Test that `transmute!` works with `!Immutable` types.
1287        let x: usize = transmute!(UnsafeCell::new(1usize));
1288        assert_eq!(x, 1);
1289        let x: UnsafeCell<usize> = transmute!(1usize);
1290        assert_eq!(x.into_inner(), 1);
1291        let x: UnsafeCell<isize> = transmute!(UnsafeCell::new(1usize));
1292        assert_eq!(x.into_inner(), 1);
1293    }
1294
1295    // A `Sized` type which doesn't implement `KnownLayout` (it is "not
1296    // `KnownLayout`", or `Nkl`).
1297    //
1298    // This permits us to test that `transmute_ref!` and `transmute_mut!` work
1299    // for types which are `Sized + !KnownLayout`. When we added support for
1300    // slice DSTs in #1924, this new support relied on `KnownLayout`, but we
1301    // need to make sure to remain backwards-compatible with code which uses
1302    // these macros with types which are `!KnownLayout`.
1303    #[derive(FromBytes, IntoBytes, Immutable, PartialEq, Eq, Debug)]
1304    #[repr(transparent)]
1305    struct Nkl<T>(T);
1306
1307    #[test]
1308    fn test_transmute_ref() {
1309        // Test that memory is transmuted as expected.
1310        let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
1311        let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
1312        let x: &[[u8; 2]; 4] = transmute_ref!(&array_of_u8s);
1313        assert_eq!(*x, array_of_arrays);
1314        let x: &[u8; 8] = transmute_ref!(&array_of_arrays);
1315        assert_eq!(*x, array_of_u8s);
1316
1317        // Test that `transmute_ref!` is legal in a const context.
1318        const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7];
1319        const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]];
1320        #[allow(clippy::redundant_static_lifetimes)]
1321        const X: &'static [[u8; 2]; 4] = transmute_ref!(&ARRAY_OF_U8S);
1322        assert_eq!(*X, ARRAY_OF_ARRAYS);
1323
1324        // Test sized -> unsized transmutation.
1325        let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
1326        let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
1327        let slice_of_arrays = &array_of_arrays[..];
1328        let x: &[[u8; 2]] = transmute_ref!(&array_of_u8s);
1329        assert_eq!(x, slice_of_arrays);
1330
1331        // Before 1.61.0, we can't define the `const fn transmute_ref` function
1332        // that we do on and after 1.61.0.
1333        #[cfg(no_zerocopy_generic_bounds_in_const_fn_1_61_0)]
1334        {
1335            // Test that `transmute_ref!` supports non-`KnownLayout` `Sized`
1336            // types.
1337            const ARRAY_OF_NKL_U8S: Nkl<[u8; 8]> = Nkl([0u8, 1, 2, 3, 4, 5, 6, 7]);
1338            const ARRAY_OF_NKL_ARRAYS: Nkl<[[u8; 2]; 4]> = Nkl([[0, 1], [2, 3], [4, 5], [6, 7]]);
1339            const X_NKL: &Nkl<[[u8; 2]; 4]> = transmute_ref!(&ARRAY_OF_NKL_U8S);
1340            assert_eq!(*X_NKL, ARRAY_OF_NKL_ARRAYS);
1341        }
1342
1343        #[cfg(not(no_zerocopy_generic_bounds_in_const_fn_1_61_0))]
1344        {
1345            // Call through a generic function to make sure our autoref
1346            // specialization trick works even when types are generic.
1347            const fn transmute_ref<T, U>(t: &T) -> &U
1348            where
1349                T: IntoBytes + Immutable,
1350                U: FromBytes + Immutable,
1351            {
1352                transmute_ref!(t)
1353            }
1354
1355            // Test that `transmute_ref!` supports non-`KnownLayout` `Sized`
1356            // types.
1357            const ARRAY_OF_NKL_U8S: Nkl<[u8; 8]> = Nkl([0u8, 1, 2, 3, 4, 5, 6, 7]);
1358            const ARRAY_OF_NKL_ARRAYS: Nkl<[[u8; 2]; 4]> = Nkl([[0, 1], [2, 3], [4, 5], [6, 7]]);
1359            const X_NKL: &Nkl<[[u8; 2]; 4]> = transmute_ref(&ARRAY_OF_NKL_U8S);
1360            assert_eq!(*X_NKL, ARRAY_OF_NKL_ARRAYS);
1361        }
1362
1363        // Test that `transmute_ref!` works on slice DSTs in and that memory is
1364        // transmuted as expected.
1365        let slice_dst_of_u8s =
1366            SliceDst::<U16, [u8; 2]>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap();
1367        let slice_dst_of_u16s =
1368            SliceDst::<U16, U16>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap();
1369        let x: &SliceDst<U16, U16> = transmute_ref!(slice_dst_of_u8s);
1370        assert_eq!(x, slice_dst_of_u16s);
1371
1372        let slice_dst_of_u8s =
1373            SliceDst::<U16, u8>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap();
1374        let x: &[u8] = transmute_ref!(slice_dst_of_u8s);
1375        assert_eq!(x, [0, 1, 2, 3, 4, 5]);
1376
1377        let x: &[u8] = transmute_ref!(slice_dst_of_u16s);
1378        assert_eq!(x, [0, 1, 2, 3, 4, 5]);
1379
1380        let x: &[U16] = transmute_ref!(slice_dst_of_u16s);
1381        let slice_of_u16s: &[U16] = <[U16]>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap();
1382        assert_eq!(x, slice_of_u16s);
1383
1384        // Test that transmuting from a type with larger trailing slice offset
1385        // and larger trailing slice element works.
1386        let bytes = &[0, 1, 2, 3, 4, 5, 6, 7][..];
1387        let slice_dst_big = SliceDst::<U32, U16>::ref_from_bytes(bytes).unwrap();
1388        let slice_dst_small = SliceDst::<U16, u8>::ref_from_bytes(bytes).unwrap();
1389        let x: &SliceDst<U16, u8> = transmute_ref!(slice_dst_big);
1390        assert_eq!(x, slice_dst_small);
1391
1392        // Test that it's legal to transmute a reference while shrinking the
1393        // lifetime (note that `X` has the lifetime `'static`).
1394        let x: &[u8; 8] = transmute_ref!(X);
1395        assert_eq!(*x, ARRAY_OF_U8S);
1396
1397        // Test that `transmute_ref!` supports decreasing alignment.
1398        let u = AU64(0);
1399        let array = [0, 0, 0, 0, 0, 0, 0, 0];
1400        let x: &[u8; 8] = transmute_ref!(&u);
1401        assert_eq!(*x, array);
1402
1403        // Test that a mutable reference can be turned into an immutable one.
1404        let mut x = 0u8;
1405        #[allow(clippy::useless_transmute)]
1406        let y: &u8 = transmute_ref!(&mut x);
1407        assert_eq!(*y, 0);
1408    }
1409
1410    #[test]
1411    fn test_try_transmute() {
1412        // Test that memory is transmuted with `try_transmute` as expected.
1413        let array_of_bools = [false, true, false, true, false, true, false, true];
1414        let array_of_arrays = [[0, 1], [0, 1], [0, 1], [0, 1]];
1415        let x: Result<[[u8; 2]; 4], _> = try_transmute!(array_of_bools);
1416        assert_eq!(x, Ok(array_of_arrays));
1417        let x: Result<[bool; 8], _> = try_transmute!(array_of_arrays);
1418        assert_eq!(x, Ok(array_of_bools));
1419
1420        // Test that `try_transmute!` works with `!Immutable` types.
1421        let x: Result<usize, _> = try_transmute!(UnsafeCell::new(1usize));
1422        assert_eq!(x.unwrap(), 1);
1423        let x: Result<UnsafeCell<usize>, _> = try_transmute!(1usize);
1424        assert_eq!(x.unwrap().into_inner(), 1);
1425        let x: Result<UnsafeCell<isize>, _> = try_transmute!(UnsafeCell::new(1usize));
1426        assert_eq!(x.unwrap().into_inner(), 1);
1427
1428        #[derive(FromBytes, IntoBytes, Debug, PartialEq)]
1429        #[repr(transparent)]
1430        struct PanicOnDrop<T>(T);
1431
1432        impl<T> Drop for PanicOnDrop<T> {
1433            fn drop(&mut self) {
1434                panic!("PanicOnDrop dropped");
1435            }
1436        }
1437
1438        // Since `try_transmute!` semantically moves its argument on failure,
1439        // the `PanicOnDrop` is not dropped, and thus this shouldn't panic.
1440        let x: Result<usize, _> = try_transmute!(PanicOnDrop(1usize));
1441        assert_eq!(x, Ok(1));
1442
1443        // Since `try_transmute!` semantically returns ownership of its argument
1444        // on failure, the `PanicOnDrop` is returned rather than dropped, and
1445        // thus this shouldn't panic.
1446        let y: Result<bool, _> = try_transmute!(PanicOnDrop(2u8));
1447        // We have to use `map_err` instead of comparing against
1448        // `Err(PanicOnDrop(2u8))` because the latter would create and then drop
1449        // its `PanicOnDrop` temporary, which would cause a panic.
1450        assert_eq!(y.as_ref().map_err(|p| &p.src.0), Err::<&bool, _>(&2u8));
1451        mem::forget(y);
1452    }
1453
1454    #[test]
1455    fn test_try_transmute_ref() {
1456        // Test that memory is transmuted with `try_transmute_ref` as expected.
1457        let array_of_bools = &[false, true, false, true, false, true, false, true];
1458        let array_of_arrays = &[[0, 1], [0, 1], [0, 1], [0, 1]];
1459        let x: Result<&[[u8; 2]; 4], _> = try_transmute_ref!(array_of_bools);
1460        assert_eq!(x, Ok(array_of_arrays));
1461        let x: Result<&[bool; 8], _> = try_transmute_ref!(array_of_arrays);
1462        assert_eq!(x, Ok(array_of_bools));
1463
1464        // Test that it's legal to transmute a reference while shrinking the
1465        // lifetime.
1466        {
1467            let x: Result<&[[u8; 2]; 4], _> = try_transmute_ref!(array_of_bools);
1468            assert_eq!(x, Ok(array_of_arrays));
1469        }
1470
1471        // Test that `try_transmute_ref!` supports decreasing alignment.
1472        let u = AU64(0);
1473        let array = [0u8, 0, 0, 0, 0, 0, 0, 0];
1474        let x: Result<&[u8; 8], _> = try_transmute_ref!(&u);
1475        assert_eq!(x, Ok(&array));
1476
1477        // Test that a mutable reference can be turned into an immutable one.
1478        let mut x = 0u8;
1479        #[allow(clippy::useless_transmute)]
1480        let y: Result<&u8, _> = try_transmute_ref!(&mut x);
1481        assert_eq!(y, Ok(&0));
1482
1483        // Test that sized types work which don't implement `KnownLayout`.
1484        let array_of_nkl_u8s = Nkl([0u8, 1, 2, 3, 4, 5, 6, 7]);
1485        let array_of_nkl_arrays = Nkl([[0, 1], [2, 3], [4, 5], [6, 7]]);
1486        let x: Result<&Nkl<[[u8; 2]; 4]>, _> = try_transmute_ref!(&array_of_nkl_u8s);
1487        assert_eq!(x, Ok(&array_of_nkl_arrays));
1488
1489        // Test sized -> unsized transmutation.
1490        let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
1491        let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
1492        let slice_of_arrays = &array_of_arrays[..];
1493        let x: Result<&[[u8; 2]], _> = try_transmute_ref!(&array_of_u8s);
1494        assert_eq!(x, Ok(slice_of_arrays));
1495
1496        // Test unsized -> unsized transmutation.
1497        let slice_dst_of_u8s =
1498            SliceDst::<U16, [u8; 2]>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap();
1499        let slice_dst_of_u16s =
1500            SliceDst::<U16, U16>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap();
1501        let x: Result<&SliceDst<U16, U16>, _> = try_transmute_ref!(slice_dst_of_u8s);
1502        assert_eq!(x, Ok(slice_dst_of_u16s));
1503    }
1504
1505    #[test]
1506    fn test_try_transmute_mut() {
1507        // Test that memory is transmuted with `try_transmute_mut` as expected.
1508        let array_of_u8s = &mut [0u8, 1, 0, 1, 0, 1, 0, 1];
1509        let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
1510        let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_u8s);
1511        assert_eq!(x, Ok(array_of_arrays));
1512
1513        let array_of_bools = &mut [false, true, false, true, false, true, false, true];
1514        let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
1515        let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays);
1516        assert_eq!(x, Ok(array_of_bools));
1517
1518        // Test that it's legal to transmute a reference while shrinking the
1519        // lifetime.
1520        let array_of_bools = &mut [false, true, false, true, false, true, false, true];
1521        let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
1522        {
1523            let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays);
1524            assert_eq!(x, Ok(array_of_bools));
1525        }
1526
1527        // Test that `try_transmute_mut!` supports decreasing alignment.
1528        let u = &mut AU64(0);
1529        let array = &mut [0u8, 0, 0, 0, 0, 0, 0, 0];
1530        let x: Result<&mut [u8; 8], _> = try_transmute_mut!(u);
1531        assert_eq!(x, Ok(array));
1532
1533        // Test that a mutable reference can be turned into an immutable one.
1534        let mut x = 0u8;
1535        #[allow(clippy::useless_transmute)]
1536        let y: Result<&mut u8, _> = try_transmute_mut!(&mut x);
1537        assert_eq!(y, Ok(&mut 0));
1538
1539        // Test that sized types work which don't implement `KnownLayout`.
1540        let mut array_of_nkl_u8s = Nkl([0u8, 1, 2, 3, 4, 5, 6, 7]);
1541        let mut array_of_nkl_arrays = Nkl([[0, 1], [2, 3], [4, 5], [6, 7]]);
1542        let x: Result<&mut Nkl<[[u8; 2]; 4]>, _> = try_transmute_mut!(&mut array_of_nkl_u8s);
1543        assert_eq!(x, Ok(&mut array_of_nkl_arrays));
1544
1545        // Test sized -> unsized transmutation.
1546        let mut array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
1547        let mut array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
1548        let slice_of_arrays = &mut array_of_arrays[..];
1549        let x: Result<&mut [[u8; 2]], _> = try_transmute_mut!(&mut array_of_u8s);
1550        assert_eq!(x, Ok(slice_of_arrays));
1551
1552        // Test unsized -> unsized transmutation.
1553        let mut bytes = [0, 1, 2, 3, 4, 5, 6];
1554        let slice_dst_of_u8s = SliceDst::<u8, [u8; 2]>::mut_from_bytes(&mut bytes[..]).unwrap();
1555        let mut bytes = [0, 1, 2, 3, 4, 5, 6];
1556        let slice_dst_of_u16s = SliceDst::<u8, U16>::mut_from_bytes(&mut bytes[..]).unwrap();
1557        let x: Result<&mut SliceDst<u8, U16>, _> = try_transmute_mut!(slice_dst_of_u8s);
1558        assert_eq!(x, Ok(slice_dst_of_u16s));
1559    }
1560
1561    #[test]
1562    fn test_transmute_mut() {
1563        // Test that memory is transmuted as expected.
1564        let mut array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
1565        let mut array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
1566        let x: &mut [[u8; 2]; 4] = transmute_mut!(&mut array_of_u8s);
1567        assert_eq!(*x, array_of_arrays);
1568        let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays);
1569        assert_eq!(*x, array_of_u8s);
1570
1571        {
1572            // Test that it's legal to transmute a reference while shrinking the
1573            // lifetime.
1574            let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays);
1575            assert_eq!(*x, array_of_u8s);
1576        }
1577
1578        // Test that `transmute_mut!` supports non-`KnownLayout` types.
1579        let mut array_of_u8s = Nkl([0u8, 1, 2, 3, 4, 5, 6, 7]);
1580        let mut array_of_arrays = Nkl([[0, 1], [2, 3], [4, 5], [6, 7]]);
1581        let x: &mut Nkl<[[u8; 2]; 4]> = transmute_mut!(&mut array_of_u8s);
1582        assert_eq!(*x, array_of_arrays);
1583        let x: &mut Nkl<[u8; 8]> = transmute_mut!(&mut array_of_arrays);
1584        assert_eq!(*x, array_of_u8s);
1585
1586        // Test that `transmute_mut!` supports decreasing alignment.
1587        let mut u = AU64(0);
1588        let array = [0, 0, 0, 0, 0, 0, 0, 0];
1589        let x: &[u8; 8] = transmute_mut!(&mut u);
1590        assert_eq!(*x, array);
1591
1592        // Test that a mutable reference can be turned into an immutable one.
1593        let mut x = 0u8;
1594        #[allow(clippy::useless_transmute)]
1595        let y: &u8 = transmute_mut!(&mut x);
1596        assert_eq!(*y, 0);
1597
1598        // Test that `transmute_mut!` works on slice DSTs in and that memory is
1599        // transmuted as expected.
1600        let mut bytes = [0, 1, 2, 3, 4, 5, 6];
1601        let slice_dst_of_u8s = SliceDst::<u8, [u8; 2]>::mut_from_bytes(&mut bytes[..]).unwrap();
1602        let mut bytes = [0, 1, 2, 3, 4, 5, 6];
1603        let slice_dst_of_u16s = SliceDst::<u8, U16>::mut_from_bytes(&mut bytes[..]).unwrap();
1604        let x: &mut SliceDst<u8, U16> = transmute_mut!(slice_dst_of_u8s);
1605        assert_eq!(x, slice_dst_of_u16s);
1606
1607        // Test that `transmute_mut!` works on slices that memory is transmuted
1608        // as expected.
1609        let array_of_u16s: &mut [u16] = &mut [0u16, 1, 2];
1610        let array_of_i16s: &mut [i16] = &mut [0i16, 1, 2];
1611        let x: &mut [i16] = transmute_mut!(array_of_u16s);
1612        assert_eq!(x, array_of_i16s);
1613
1614        // Test that transmuting from a type with larger trailing slice offset
1615        // and larger trailing slice element works.
1616        let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7];
1617        let slice_dst_big = SliceDst::<U32, U16>::mut_from_bytes(&mut bytes[..]).unwrap();
1618        let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7];
1619        let slice_dst_small = SliceDst::<U16, u8>::mut_from_bytes(&mut bytes[..]).unwrap();
1620        let x: &mut SliceDst<U16, u8> = transmute_mut!(slice_dst_big);
1621        assert_eq!(x, slice_dst_small);
1622
1623        // Test sized -> unsized transmutation.
1624        let mut array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
1625        let mut array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
1626        let slice_of_arrays = &mut array_of_arrays[..];
1627        let x: &mut [[u8; 2]] = transmute_mut!(&mut array_of_u8s);
1628        assert_eq!(x, slice_of_arrays);
1629    }
1630
1631    #[test]
1632    fn test_macros_evaluate_args_once() {
1633        let mut ctr = 0;
1634        #[allow(clippy::useless_transmute)]
1635        let _: usize = transmute!({
1636            ctr += 1;
1637            0usize
1638        });
1639        assert_eq!(ctr, 1);
1640
1641        let mut ctr = 0;
1642        let _: &usize = transmute_ref!({
1643            ctr += 1;
1644            &0usize
1645        });
1646        assert_eq!(ctr, 1);
1647
1648        let mut ctr: usize = 0;
1649        let _: &mut usize = transmute_mut!({
1650            ctr += 1;
1651            &mut ctr
1652        });
1653        assert_eq!(ctr, 1);
1654
1655        let mut ctr = 0;
1656        #[allow(clippy::useless_transmute)]
1657        let _: usize = try_transmute!({
1658            ctr += 1;
1659            0usize
1660        })
1661        .unwrap();
1662        assert_eq!(ctr, 1);
1663    }
1664
1665    #[test]
1666    fn test_include_value() {
1667        const AS_U32: u32 = include_value!("../testdata/include_value/data");
1668        assert_eq!(AS_U32, u32::from_ne_bytes([b'a', b'b', b'c', b'd']));
1669        const AS_I32: i32 = include_value!("../testdata/include_value/data");
1670        assert_eq!(AS_I32, i32::from_ne_bytes([b'a', b'b', b'c', b'd']));
1671    }
1672
1673    #[test]
1674    #[allow(non_camel_case_types, unreachable_pub, dead_code)]
1675    fn test_cryptocorrosion_derive_traits() {
1676        // Test the set of invocations added in
1677        // https://github.com/cryptocorrosion/cryptocorrosion/pull/85
1678
1679        fn assert_impls<T: FromBytes + IntoBytes + Immutable>() {}
1680
1681        cryptocorrosion_derive_traits! {
1682            #[repr(C)]
1683            #[derive(Clone, Copy)]
1684            pub union vec128_storage {
1685                d: [u32; 4],
1686                q: [u64; 2],
1687            }
1688        }
1689
1690        assert_impls::<vec128_storage>();
1691
1692        cryptocorrosion_derive_traits! {
1693            #[repr(transparent)]
1694            #[derive(Copy, Clone, Debug, PartialEq)]
1695            pub struct u32x4_generic([u32; 4]);
1696        }
1697
1698        assert_impls::<u32x4_generic>();
1699
1700        cryptocorrosion_derive_traits! {
1701            #[repr(transparent)]
1702            #[derive(Copy, Clone, Debug, PartialEq)]
1703            pub struct u64x2_generic([u64; 2]);
1704        }
1705
1706        assert_impls::<u64x2_generic>();
1707
1708        cryptocorrosion_derive_traits! {
1709            #[repr(transparent)]
1710            #[derive(Copy, Clone, Debug, PartialEq)]
1711            pub struct u128x1_generic([u128; 1]);
1712        }
1713
1714        assert_impls::<u128x1_generic>();
1715
1716        cryptocorrosion_derive_traits! {
1717            #[repr(transparent)]
1718            #[derive(Copy, Clone, Default)]
1719            #[allow(non_camel_case_types)]
1720            pub struct x2<W, G>(pub [W; 2], PhantomData<G>);
1721        }
1722
1723        enum NotZerocopy {}
1724        assert_impls::<x2<(), NotZerocopy>>();
1725
1726        cryptocorrosion_derive_traits! {
1727            #[repr(transparent)]
1728            #[derive(Copy, Clone, Default)]
1729            #[allow(non_camel_case_types)]
1730            pub struct x4<W>(pub [W; 4]);
1731        }
1732
1733        assert_impls::<x4<()>>();
1734
1735        #[cfg(feature = "simd")]
1736        #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1737        {
1738            #[cfg(target_arch = "x86")]
1739            use core::arch::x86::{__m128i, __m256i};
1740            #[cfg(target_arch = "x86_64")]
1741            use core::arch::x86_64::{__m128i, __m256i};
1742
1743            cryptocorrosion_derive_traits! {
1744                #[repr(C)]
1745                #[derive(Copy, Clone)]
1746                pub struct X4(__m128i, __m128i, __m128i, __m128i);
1747            }
1748
1749            assert_impls::<X4>();
1750
1751            cryptocorrosion_derive_traits! {
1752                #[repr(C)]
1753                /// Generic wrapper for unparameterized storage of any of the
1754                /// possible impls. Converting into and out of this type should
1755                /// be essentially free, although it may be more aligned than a
1756                /// particular impl requires.
1757                #[allow(non_camel_case_types)]
1758                #[derive(Copy, Clone)]
1759                pub union vec128_storage {
1760                    u32x4: [u32; 4],
1761                    u64x2: [u64; 2],
1762                    u128x1: [u128; 1],
1763                    sse2: __m128i,
1764                }
1765            }
1766
1767            assert_impls::<vec128_storage>();
1768
1769            cryptocorrosion_derive_traits! {
1770                #[repr(transparent)]
1771                #[allow(non_camel_case_types)]
1772                #[derive(Copy, Clone)]
1773                pub struct vec<S3, S4, NI> {
1774                    x: __m128i,
1775                    s3: PhantomData<S3>,
1776                    s4: PhantomData<S4>,
1777                    ni: PhantomData<NI>,
1778                }
1779            }
1780
1781            assert_impls::<vec<NotZerocopy, NotZerocopy, NotZerocopy>>();
1782
1783            cryptocorrosion_derive_traits! {
1784                #[repr(transparent)]
1785                #[derive(Copy, Clone)]
1786                pub struct u32x4x2_avx2<NI> {
1787                    x: __m256i,
1788                    ni: PhantomData<NI>,
1789                }
1790            }
1791
1792            assert_impls::<u32x4x2_avx2<NotZerocopy>>();
1793        }
1794
1795        // Make sure that our derive works for `#[repr(C)]` structs even though
1796        // cryptocorrosion doesn't currently have any.
1797        cryptocorrosion_derive_traits! {
1798            #[repr(C)]
1799            #[derive(Copy, Clone, Debug, PartialEq)]
1800            pub struct ReprC(u8, u8, u16);
1801        }
1802    }
1803}