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