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