Skip to main content

zerocopy/
macros.rs

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