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