zerocopy/macros.rs
1// Copyright 2024 The Fuchsia Authors
2//
3// Licensed under the 2-Clause BSD License <LICENSE-BSD or
4// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
5// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
6// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
7// This file may not be copied, modified, or distributed except according to
8// those terms.
9
10/// Safely transmutes a value of one type to a value of another type of the same
11/// size.
12///
13/// This macro behaves like an invocation of this function:
14///
15/// ```ignore
16/// const fn transmute<Src, Dst>(src: Src) -> Dst
17/// where
18/// Src: IntoBytes,
19/// Dst: FromBytes,
20/// size_of::<Src>() == size_of::<Dst>(),
21/// {
22/// # /*
23/// ...
24/// # */
25/// }
26/// ```
27///
28/// However, unlike a function, this macro can only be invoked when the types of
29/// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are
30/// inferred from the calling context; they cannot be explicitly specified in
31/// the macro invocation.
32///
33/// Note that the `Src` produced by the expression `$e` will *not* be dropped.
34/// Semantically, its bits will be copied into a new value of type `Dst`, the
35/// original `Src` will be forgotten, and the value of type `Dst` will be
36/// returned.
37///
38/// # Examples
39///
40/// ```
41/// # use zerocopy::transmute;
42/// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
43///
44/// let two_dimensional: [[u8; 4]; 2] = transmute!(one_dimensional);
45///
46/// assert_eq!(two_dimensional, [[0, 1, 2, 3], [4, 5, 6, 7]]);
47/// ```
48///
49/// # Use in `const` contexts
50///
51/// This macro can be invoked in `const` contexts.
52#[macro_export]
53macro_rules! transmute {
54 ($e:expr) => {{
55 // NOTE: This must be a macro (rather than a function with trait bounds)
56 // because there's no way, in a generic context, to enforce that two
57 // types have the same size. `core::mem::transmute` uses compiler magic
58 // to enforce this so long as the types are concrete.
59
60 let e = $e;
61 if false {
62 // This branch, though never taken, ensures that the type of `e` is
63 // `IntoBytes` and that the type of this macro invocation expression
64 // is `FromBytes`.
65
66 struct AssertIsIntoBytes<T: $crate::IntoBytes>(T);
67 let _ = AssertIsIntoBytes(e);
68
69 struct AssertIsFromBytes<U: $crate::FromBytes>(U);
70 #[allow(unused, unreachable_code)]
71 let u = AssertIsFromBytes(loop {});
72 u.0
73 } else {
74 // SAFETY: `core::mem::transmute` ensures that the type of `e` and
75 // the type of this macro invocation expression have the same size.
76 // We know this transmute is safe thanks to the `IntoBytes` and
77 // `FromBytes` bounds enforced by the `false` branch.
78 //
79 // We use this reexport of `core::mem::transmute` because we know it
80 // will always be available for crates which are using the 2015
81 // edition of Rust. By contrast, if we were to use
82 // `std::mem::transmute`, this macro would not work for such crates
83 // in `no_std` contexts, and if we were to use
84 // `core::mem::transmute`, this macro would not work in `std`
85 // contexts in which `core` was not manually imported. This is not a
86 // problem for 2018 edition crates.
87 let u = unsafe {
88 // Clippy: We can't annotate the types; this macro is designed
89 // to infer the types from the calling context.
90 #[allow(clippy::missing_transmute_annotations)]
91 $crate::util::macro_util::core_reexport::mem::transmute(e)
92 };
93 $crate::util::macro_util::must_use(u)
94 }
95 }}
96}
97
98/// Safely transmutes a mutable or immutable reference of one type to an
99/// immutable reference of another type of the same size and compatible
100/// alignment.
101///
102/// This macro behaves like an invocation of this function:
103///
104/// ```ignore
105/// const fn transmute_ref<'src, 'dst, Src, Dst>(src: &'src Src) -> &'dst Dst
106/// where
107/// 'src: 'dst,
108/// Src: IntoBytes + Immutable,
109/// Dst: FromBytes + Immutable,
110/// size_of::<Src>() == size_of::<Dst>(),
111/// align_of::<Src>() >= align_of::<Dst>(),
112/// {
113/// # /*
114/// ...
115/// # */
116/// }
117/// ```
118///
119/// However, unlike a function, this macro can only be invoked when the types of
120/// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are
121/// inferred from the calling context; they cannot be explicitly specified in
122/// the macro invocation.
123///
124/// # Examples
125///
126/// ```
127/// # use zerocopy::transmute_ref;
128/// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
129///
130/// let two_dimensional: &[[u8; 4]; 2] = transmute_ref!(&one_dimensional);
131///
132/// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]);
133/// ```
134///
135/// # Use in `const` contexts
136///
137/// This macro can be invoked in `const` contexts.
138///
139/// # Alignment increase error message
140///
141/// Because of limitations on macros, the error message generated when
142/// `transmute_ref!` is used to transmute from a type of lower alignment to a
143/// type of higher alignment is somewhat confusing. For example, the following
144/// code:
145///
146/// ```compile_fail
147/// const INCREASE_ALIGNMENT: &u16 = zerocopy::transmute_ref!(&[0u8; 2]);
148/// ```
149///
150/// ...generates the following error:
151///
152/// ```text
153/// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
154/// --> src/lib.rs:1524:34
155/// |
156/// 5 | const INCREASE_ALIGNMENT: &u16 = zerocopy::transmute_ref!(&[0u8; 2]);
157/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
158/// |
159/// = note: source type: `AlignOf<[u8; 2]>` (8 bits)
160/// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits)
161/// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
162/// ```
163///
164/// This is saying that `max(align_of::<T>(), align_of::<U>()) !=
165/// align_of::<T>()`, which is equivalent to `align_of::<T>() <
166/// align_of::<U>()`.
167#[macro_export]
168macro_rules! transmute_ref {
169 ($e:expr) => {{
170 // NOTE: This must be a macro (rather than a function with trait bounds)
171 // because there's no way, in a generic context, to enforce that two
172 // types have the same size or alignment.
173
174 // Ensure that the source type is a reference or a mutable reference
175 // (note that mutable references are implicitly reborrowed here).
176 let e: &_ = $e;
177
178 #[allow(unused, clippy::diverging_sub_expression)]
179 if false {
180 // This branch, though never taken, ensures that the type of `e` is
181 // `&T` where `T: 't + Sized + IntoBytes + Immutable`, that the type of
182 // this macro expression is `&U` where `U: 'u + Sized + FromBytes +
183 // Immutable`, and that `'t` outlives `'u`.
184
185 struct AssertSrcIsSized<'a, T: ::core::marker::Sized>(&'a T);
186 struct AssertSrcIsIntoBytes<'a, T: ?::core::marker::Sized + $crate::IntoBytes>(&'a T);
187 struct AssertSrcIsImmutable<'a, T: ?::core::marker::Sized + $crate::Immutable>(&'a T);
188 struct AssertDstIsSized<'a, T: ::core::marker::Sized>(&'a T);
189 struct AssertDstIsFromBytes<'a, U: ?::core::marker::Sized + $crate::FromBytes>(&'a U);
190 struct AssertDstIsImmutable<'a, T: ?::core::marker::Sized + $crate::Immutable>(&'a T);
191
192 let _ = AssertSrcIsSized(e);
193 let _ = AssertSrcIsIntoBytes(e);
194 let _ = AssertSrcIsImmutable(e);
195
196 if true {
197 #[allow(unused, unreachable_code)]
198 let u = AssertDstIsSized(loop {});
199 u.0
200 } else if true {
201 #[allow(unused, unreachable_code)]
202 let u = AssertDstIsFromBytes(loop {});
203 u.0
204 } else {
205 #[allow(unused, unreachable_code)]
206 let u = AssertDstIsImmutable(loop {});
207 u.0
208 }
209 } else if false {
210 // This branch, though never taken, ensures that `size_of::<T>() ==
211 // size_of::<U>()` and that that `align_of::<T>() >=
212 // align_of::<U>()`.
213
214 // `t` is inferred to have type `T` because it's assigned to `e` (of
215 // type `&T`) as `&t`.
216 let mut t = loop {};
217 e = &t;
218
219 // `u` is inferred to have type `U` because it's used as `&u` as the
220 // value returned from this branch.
221 let u;
222
223 $crate::assert_size_eq!(t, u);
224 $crate::assert_align_gt_eq!(t, u);
225
226 &u
227 } else {
228 // SAFETY: For source type `Src` and destination type `Dst`:
229 // - We know that `Src: IntoBytes + Immutable` and `Dst: FromBytes +
230 // Immutable` thanks to the uses of `AssertSrcIsIntoBytes`,
231 // `AssertSrcIsImmutable`, `AssertDstIsFromBytes`, and
232 // `AssertDstIsImmutable` above.
233 // - We know that `size_of::<Src>() == size_of::<Dst>()` thanks to
234 // the use of `assert_size_eq!` above.
235 // - We know that `align_of::<Src>() >= align_of::<Dst>()` thanks to
236 // the use of `assert_align_gt_eq!` above.
237 let u = unsafe { $crate::util::macro_util::transmute_ref(e) };
238 $crate::util::macro_util::must_use(u)
239 }
240 }}
241}
242
243/// Safely transmutes a mutable reference of one type to a mutable reference of
244/// another type of the same size and compatible alignment.
245///
246/// This macro behaves like an invocation of this function:
247///
248/// ```ignore
249/// const fn transmute_mut<'src, 'dst, Src, Dst>(src: &'src mut Src) -> &'dst mut Dst
250/// where
251/// 'src: 'dst,
252/// Src: FromBytes + IntoBytes + Immutable,
253/// Dst: FromBytes + IntoBytes + Immutable,
254/// size_of::<Src>() == size_of::<Dst>(),
255/// align_of::<Src>() >= align_of::<Dst>(),
256/// {
257/// # /*
258/// ...
259/// # */
260/// }
261/// ```
262///
263/// However, unlike a function, this macro can only be invoked when the types of
264/// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are
265/// inferred from the calling context; they cannot be explicitly specified in
266/// the macro invocation.
267///
268/// # Examples
269///
270/// ```
271/// # use zerocopy::transmute_mut;
272/// let mut one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
273///
274/// let two_dimensional: &mut [[u8; 4]; 2] = transmute_mut!(&mut one_dimensional);
275///
276/// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]);
277///
278/// two_dimensional.reverse();
279///
280/// assert_eq!(one_dimensional, [4, 5, 6, 7, 0, 1, 2, 3]);
281/// ```
282///
283/// # Use in `const` contexts
284///
285/// This macro can be invoked in `const` contexts.
286///
287/// # Alignment increase error message
288///
289/// Because of limitations on macros, the error message generated when
290/// `transmute_mut!` is used to transmute from a type of lower alignment to a
291/// type of higher alignment is somewhat confusing. For example, the following
292/// code:
293///
294/// ```compile_fail
295/// const INCREASE_ALIGNMENT: &mut u16 = zerocopy::transmute_mut!(&mut [0u8; 2]);
296/// ```
297///
298/// ...generates the following error:
299///
300/// ```text
301/// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
302/// --> src/lib.rs:1524:34
303/// |
304/// 5 | const INCREASE_ALIGNMENT: &mut u16 = zerocopy::transmute_mut!(&mut [0u8; 2]);
305/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
306/// |
307/// = note: source type: `AlignOf<[u8; 2]>` (8 bits)
308/// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits)
309/// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
310/// ```
311///
312/// This is saying that `max(align_of::<T>(), align_of::<U>()) !=
313/// align_of::<T>()`, which is equivalent to `align_of::<T>() <
314/// align_of::<U>()`.
315#[macro_export]
316macro_rules! transmute_mut {
317 ($e:expr) => {{
318 // NOTE: This must be a macro (rather than a function with trait bounds)
319 // because there's no way, in a generic context, to enforce that two
320 // types have the same size or alignment.
321
322 // Ensure that the source type is a mutable reference.
323 let e: &mut _ = $e;
324
325 #[allow(unused, clippy::diverging_sub_expression)]
326 if false {
327 // This branch, though never taken, ensures that the type of `e` is
328 // `&mut T` where `T: 't + Sized + FromBytes + IntoBytes + Immutable`
329 // and that the type of this macro expression is `&mut U` where `U:
330 // 'u + Sized + FromBytes + IntoBytes + Immutable`.
331
332 // We use immutable references here rather than mutable so that, if
333 // this macro is used in a const context (in which, as of this
334 // writing, mutable references are banned), the error message
335 // appears to originate in the user's code rather than in the
336 // internals of this macro.
337 struct AssertSrcIsSized<'a, T: ::core::marker::Sized>(&'a T);
338 struct AssertSrcIsFromBytes<'a, T: ?::core::marker::Sized + $crate::FromBytes>(&'a T);
339 struct AssertSrcIsIntoBytes<'a, T: ?::core::marker::Sized + $crate::IntoBytes>(&'a T);
340 struct AssertDstIsSized<'a, T: ::core::marker::Sized>(&'a T);
341 struct AssertDstIsFromBytes<'a, T: ?::core::marker::Sized + $crate::FromBytes>(&'a T);
342 struct AssertDstIsIntoBytes<'a, T: ?::core::marker::Sized + $crate::IntoBytes>(&'a T);
343
344 if true {
345 let _ = AssertSrcIsSized(&*e);
346 } else if true {
347 let _ = AssertSrcIsFromBytes(&*e);
348 } else {
349 let _ = AssertSrcIsIntoBytes(&*e);
350 }
351
352 if true {
353 #[allow(unused, unreachable_code)]
354 let u = AssertDstIsSized(loop {});
355 &mut *u.0
356 } else if true {
357 #[allow(unused, unreachable_code)]
358 let u = AssertDstIsFromBytes(loop {});
359 &mut *u.0
360 } else {
361 #[allow(unused, unreachable_code)]
362 let u = AssertDstIsIntoBytes(loop {});
363 &mut *u.0
364 }
365 } else if false {
366 // This branch, though never taken, ensures that `size_of::<T>() ==
367 // size_of::<U>()` and that that `align_of::<T>() >=
368 // align_of::<U>()`.
369
370 // `t` is inferred to have type `T` because it's assigned to `e` (of
371 // type `&mut T`) as `&mut t`.
372 let mut t = loop {};
373 e = &mut t;
374
375 // `u` is inferred to have type `U` because it's used as `&mut u` as
376 // the value returned from this branch.
377 let u;
378
379 $crate::assert_size_eq!(t, u);
380 $crate::assert_align_gt_eq!(t, u);
381
382 &mut u
383 } else {
384 // SAFETY: For source type `Src` and destination type `Dst`:
385 // - We know that `size_of::<Src>() == size_of::<Dst>()` thanks to
386 // the use of `assert_size_eq!` above.
387 // - We know that `align_of::<Src>() >= align_of::<Dst>()` thanks to
388 // the use of `assert_align_gt_eq!` above.
389 let u = unsafe { $crate::util::macro_util::transmute_mut(e) };
390 $crate::util::macro_util::must_use(u)
391 }
392 }}
393}
394
395/// Conditionally transmutes a value of one type to a value of another type of
396/// the same size.
397///
398/// This macro behaves like an invocation of this function:
399///
400/// ```ignore
401/// fn try_transmute<Src, Dst>(src: Src) -> Result<Dst, ValidityError<Src, Dst>>
402/// where
403/// Src: IntoBytes,
404/// Dst: TryFromBytes,
405/// size_of::<Src>() == size_of::<Dst>(),
406/// {
407/// # /*
408/// ...
409/// # */
410/// }
411/// ```
412///
413/// However, unlike a function, this macro can only be invoked when the types of
414/// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are
415/// inferred from the calling context; they cannot be explicitly specified in
416/// the macro invocation.
417///
418/// Note that the `Src` produced by the expression `$e` will *not* be dropped.
419/// Semantically, its bits will be copied into a new value of type `Dst`, the
420/// original `Src` will be forgotten, and the value of type `Dst` will be
421/// returned.
422///
423/// # Examples
424///
425/// ```
426/// # use zerocopy::*;
427/// // 0u8 → bool = false
428/// assert_eq!(try_transmute!(0u8), Ok(false));
429///
430/// // 1u8 → bool = true
431/// assert_eq!(try_transmute!(1u8), Ok(true));
432///
433/// // 2u8 → bool = error
434/// assert!(matches!(
435/// try_transmute!(2u8),
436/// Result::<bool, _>::Err(ValidityError { .. })
437/// ));
438/// ```
439#[macro_export]
440macro_rules! try_transmute {
441 ($e:expr) => {{
442 // NOTE: This must be a macro (rather than a function with trait bounds)
443 // because there's no way, in a generic context, to enforce that two
444 // types have the same size. `core::mem::transmute` uses compiler magic
445 // to enforce this so long as the types are concrete.
446
447 let e = $e;
448 if false {
449 // Check that the sizes of the source and destination types are
450 // equal.
451
452 // SAFETY: This code is never executed.
453 Ok(unsafe {
454 // Clippy: We can't annotate the types; this macro is designed
455 // to infer the types from the calling context.
456 #[allow(clippy::missing_transmute_annotations)]
457 $crate::util::macro_util::core_reexport::mem::transmute(e)
458 })
459 } else {
460 $crate::util::macro_util::try_transmute::<_, _>(e)
461 }
462 }}
463}
464
465/// Conditionally transmutes a mutable or immutable reference of one type to an
466/// immutable reference of another type of the same size and compatible
467/// alignment.
468///
469/// This macro behaves like an invocation of this function:
470///
471/// ```ignore
472/// fn try_transmute_ref<Src, Dst>(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>>
473/// where
474/// Src: IntoBytes + Immutable,
475/// Dst: TryFromBytes + Immutable,
476/// size_of::<Src>() == size_of::<Dst>(),
477/// align_of::<Src>() >= align_of::<Dst>(),
478/// {
479/// # /*
480/// ...
481/// # */
482/// }
483/// ```
484///
485/// However, unlike a function, this macro can only be invoked when the types of
486/// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are
487/// inferred from the calling context; they cannot be explicitly specified in
488/// the macro invocation.
489///
490/// # Examples
491///
492/// ```
493/// # use zerocopy::*;
494/// // 0u8 → bool = false
495/// assert_eq!(try_transmute_ref!(&0u8), Ok(&false));
496///
497/// // 1u8 → bool = true
498/// assert_eq!(try_transmute_ref!(&1u8), Ok(&true));
499///
500/// // 2u8 → bool = error
501/// assert!(matches!(
502/// try_transmute_ref!(&2u8),
503/// Result::<&bool, _>::Err(ValidityError { .. })
504/// ));
505/// ```
506///
507/// # Alignment increase error message
508///
509/// Because of limitations on macros, the error message generated when
510/// `try_transmute_ref!` is used to transmute from a type of lower alignment to
511/// a type of higher alignment is somewhat confusing. For example, the following
512/// code:
513///
514/// ```compile_fail
515/// let increase_alignment: Result<&u16, _> = zerocopy::try_transmute_ref!(&[0u8; 2]);
516/// ```
517///
518/// ...generates the following error:
519///
520/// ```text
521/// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
522/// --> example.rs:1:47
523/// |
524/// 1 | let increase_alignment: Result<&u16, _> = zerocopy::try_transmute_ref!(&[0u8; 2]);
525/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
526/// |
527/// = note: source type: `AlignOf<[u8; 2]>` (8 bits)
528/// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits)
529/// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `zerocopy::try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)/// ```
530/// ```
531///
532/// This is saying that `max(align_of::<T>(), align_of::<U>()) !=
533/// align_of::<T>()`, which is equivalent to `align_of::<T>() <
534/// align_of::<U>()`.
535#[macro_export]
536macro_rules! try_transmute_ref {
537 ($e:expr) => {{
538 // NOTE: This must be a macro (rather than a function with trait bounds)
539 // because there's no way, in a generic context, to enforce that two
540 // types have the same size. `core::mem::transmute` uses compiler magic
541 // to enforce this so long as the types are concrete.
542
543 // Ensure that the source type is a reference or a mutable reference
544 // (note that mutable references are implicitly reborrowed here).
545 let e: &_ = $e;
546
547 #[allow(unreachable_code, unused, clippy::diverging_sub_expression)]
548 if false {
549 // This branch, though never taken, ensures that `size_of::<T>() ==
550 // size_of::<U>()` and that that `align_of::<T>() >=
551 // align_of::<U>()`.
552
553 // `t` is inferred to have type `T` because it's assigned to `e` (of
554 // type `&T`) as `&t`.
555 let mut t = loop {};
556 e = &t;
557
558 // `u` is inferred to have type `U` because it's used as `Ok(&u)` as
559 // the value returned from this branch.
560 let u;
561
562 $crate::assert_size_eq!(t, u);
563 $crate::assert_align_gt_eq!(t, u);
564
565 Ok(&u)
566 } else {
567 $crate::util::macro_util::try_transmute_ref::<_, _>(e)
568 }
569 }}
570}
571
572/// Conditionally transmutes a mutable reference of one type to a mutable
573/// reference of another type of the same size and compatible alignment.
574///
575/// This macro behaves like an invocation of this function:
576///
577/// ```ignore
578/// fn try_transmute_mut<Src, Dst>(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>>
579/// where
580/// Src: IntoBytes,
581/// Dst: TryFromBytes,
582/// size_of::<Src>() == size_of::<Dst>(),
583/// align_of::<Src>() >= align_of::<Dst>(),
584/// {
585/// # /*
586/// ...
587/// # */
588/// }
589/// ```
590///
591/// However, unlike a function, this macro can only be invoked when the types of
592/// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are
593/// inferred from the calling context; they cannot be explicitly specified in
594/// the macro invocation.
595///
596/// # Examples
597///
598/// ```
599/// # use zerocopy::*;
600/// // 0u8 → bool = false
601/// let src = &mut 0u8;
602/// assert_eq!(try_transmute_mut!(src), Ok(&mut false));
603///
604/// // 1u8 → bool = true
605/// let src = &mut 1u8;
606/// assert_eq!(try_transmute_mut!(src), Ok(&mut true));
607///
608/// // 2u8 → bool = error
609/// let src = &mut 2u8;
610/// assert!(matches!(
611/// try_transmute_mut!(src),
612/// Result::<&mut bool, _>::Err(ValidityError { .. })
613/// ));
614/// ```
615///
616/// # Alignment increase error message
617///
618/// Because of limitations on macros, the error message generated when
619/// `try_transmute_ref!` is used to transmute from a type of lower alignment to
620/// a type of higher alignment is somewhat confusing. For example, the following
621/// code:
622///
623/// ```compile_fail
624/// let src = &mut [0u8; 2];
625/// let increase_alignment: Result<&mut u16, _> = zerocopy::try_transmute_mut!(src);
626/// ```
627///
628/// ...generates the following error:
629///
630/// ```text
631/// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
632/// --> example.rs:2:51
633/// |
634/// 2 | let increase_alignment: Result<&mut u16, _> = zerocopy::try_transmute_mut!(src);
635/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
636/// |
637/// = note: source type: `AlignOf<[u8; 2]>` (8 bits)
638/// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits)
639/// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `zerocopy::try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
640/// ```
641///
642/// This is saying that `max(align_of::<T>(), align_of::<U>()) !=
643/// align_of::<T>()`, which is equivalent to `align_of::<T>() <
644/// align_of::<U>()`.
645#[macro_export]
646macro_rules! try_transmute_mut {
647 ($e:expr) => {{
648 // NOTE: This must be a macro (rather than a function with trait bounds)
649 // because there's no way, in a generic context, to enforce that two
650 // types have the same size. `core::mem::transmute` uses compiler magic
651 // to enforce this so long as the types are concrete.
652
653 // Ensure that the source type is a mutable reference.
654 let e: &mut _ = $e;
655
656 #[allow(unreachable_code, unused, clippy::diverging_sub_expression)]
657 if false {
658 // This branch, though never taken, ensures that `size_of::<T>() ==
659 // size_of::<U>()` and that that `align_of::<T>() >=
660 // align_of::<U>()`.
661
662 // `t` is inferred to have type `T` because it's assigned to `e` (of
663 // type `&mut T`) as `&mut t`.
664 let mut t = loop {};
665 e = &mut t;
666
667 // `u` is inferred to have type `U` because it's used as `Ok(&mut
668 // u)` as the value returned from this branch.
669 let u;
670
671 $crate::assert_size_eq!(t, u);
672 $crate::assert_align_gt_eq!(t, u);
673
674 Ok(&mut u)
675 } else {
676 $crate::util::macro_util::try_transmute_mut::<_, _>(e)
677 }
678 }}
679}
680
681/// Includes a file and safely transmutes it to a value of an arbitrary type.
682///
683/// The file will be included as a byte array, `[u8; N]`, which will be
684/// transmuted to another type, `T`. `T` is inferred from the calling context,
685/// and must implement [`FromBytes`].
686///
687/// The file is located relative to the current file (similarly to how modules
688/// are found). The provided path is interpreted in a platform-specific way at
689/// compile time. So, for instance, an invocation with a Windows path containing
690/// backslashes `\` would not compile correctly on Unix.
691///
692/// `include_value!` is ignorant of byte order. For byte order-aware types, see
693/// the [`byteorder`] module.
694///
695/// [`FromBytes`]: crate::FromBytes
696/// [`byteorder`]: crate::byteorder
697///
698/// # Examples
699///
700/// Assume there are two files in the same directory with the following
701/// contents:
702///
703/// File `data` (no trailing newline):
704///
705/// ```text
706/// abcd
707/// ```
708///
709/// File `main.rs`:
710///
711/// ```rust
712/// use zerocopy::include_value;
713/// # macro_rules! include_value {
714/// # ($file:expr) => { zerocopy::include_value!(concat!("../testdata/include_value/", $file)) };
715/// # }
716///
717/// fn main() {
718/// let as_u32: u32 = include_value!("data");
719/// assert_eq!(as_u32, u32::from_ne_bytes([b'a', b'b', b'c', b'd']));
720/// let as_i32: i32 = include_value!("data");
721/// assert_eq!(as_i32, i32::from_ne_bytes([b'a', b'b', b'c', b'd']));
722/// }
723/// ```
724///
725/// # Use in `const` contexts
726///
727/// This macro can be invoked in `const` contexts.
728#[doc(alias("include_bytes", "include_data", "include_type"))]
729#[macro_export]
730macro_rules! include_value {
731 ($file:expr $(,)?) => {
732 $crate::transmute!(*::core::include_bytes!($file))
733 };
734}
735
736#[cfg(test)]
737mod tests {
738 use crate::util::testutil::*;
739 use crate::*;
740
741 #[test]
742 fn test_transmute() {
743 // Test that memory is transmuted as expected.
744 let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
745 let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
746 let x: [[u8; 2]; 4] = transmute!(array_of_u8s);
747 assert_eq!(x, array_of_arrays);
748 let x: [u8; 8] = transmute!(array_of_arrays);
749 assert_eq!(x, array_of_u8s);
750
751 // Test that the source expression's value is forgotten rather than
752 // dropped.
753 #[derive(IntoBytes)]
754 #[repr(transparent)]
755 struct PanicOnDrop(());
756 impl Drop for PanicOnDrop {
757 fn drop(&mut self) {
758 panic!("PanicOnDrop::drop");
759 }
760 }
761 #[allow(clippy::let_unit_value)]
762 let _: () = transmute!(PanicOnDrop(()));
763
764 // Test that `transmute!` is legal in a const context.
765 const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7];
766 const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]];
767 const X: [[u8; 2]; 4] = transmute!(ARRAY_OF_U8S);
768 assert_eq!(X, ARRAY_OF_ARRAYS);
769
770 // Test that `transmute!` works with `!Immutable` types.
771 let x: usize = transmute!(UnsafeCell::new(1usize));
772 assert_eq!(x, 1);
773 let x: UnsafeCell<usize> = transmute!(1usize);
774 assert_eq!(x.into_inner(), 1);
775 let x: UnsafeCell<isize> = transmute!(UnsafeCell::new(1usize));
776 assert_eq!(x.into_inner(), 1);
777 }
778
779 #[test]
780 fn test_transmute_ref() {
781 // Test that memory is transmuted as expected.
782 let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
783 let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
784 let x: &[[u8; 2]; 4] = transmute_ref!(&array_of_u8s);
785 assert_eq!(*x, array_of_arrays);
786 let x: &[u8; 8] = transmute_ref!(&array_of_arrays);
787 assert_eq!(*x, array_of_u8s);
788
789 // Test that `transmute_ref!` is legal in a const context.
790 const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7];
791 const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]];
792 #[allow(clippy::redundant_static_lifetimes)]
793 const X: &'static [[u8; 2]; 4] = transmute_ref!(&ARRAY_OF_U8S);
794 assert_eq!(*X, ARRAY_OF_ARRAYS);
795
796 // Test that it's legal to transmute a reference while shrinking the
797 // lifetime (note that `X` has the lifetime `'static`).
798 let x: &[u8; 8] = transmute_ref!(X);
799 assert_eq!(*x, ARRAY_OF_U8S);
800
801 // Test that `transmute_ref!` supports decreasing alignment.
802 let u = AU64(0);
803 let array = [0, 0, 0, 0, 0, 0, 0, 0];
804 let x: &[u8; 8] = transmute_ref!(&u);
805 assert_eq!(*x, array);
806
807 // Test that a mutable reference can be turned into an immutable one.
808 let mut x = 0u8;
809 #[allow(clippy::useless_transmute)]
810 let y: &u8 = transmute_ref!(&mut x);
811 assert_eq!(*y, 0);
812 }
813
814 #[test]
815 fn test_try_transmute() {
816 // Test that memory is transmuted with `try_transmute` as expected.
817 let array_of_bools = [false, true, false, true, false, true, false, true];
818 let array_of_arrays = [[0, 1], [0, 1], [0, 1], [0, 1]];
819 let x: Result<[[u8; 2]; 4], _> = try_transmute!(array_of_bools);
820 assert_eq!(x, Ok(array_of_arrays));
821 let x: Result<[bool; 8], _> = try_transmute!(array_of_arrays);
822 assert_eq!(x, Ok(array_of_bools));
823
824 // Test that `try_transmute!` works with `!Immutable` types.
825 let x: Result<usize, _> = try_transmute!(UnsafeCell::new(1usize));
826 assert_eq!(x.unwrap(), 1);
827 let x: Result<UnsafeCell<usize>, _> = try_transmute!(1usize);
828 assert_eq!(x.unwrap().into_inner(), 1);
829 let x: Result<UnsafeCell<isize>, _> = try_transmute!(UnsafeCell::new(1usize));
830 assert_eq!(x.unwrap().into_inner(), 1);
831
832 #[derive(FromBytes, IntoBytes, Debug, PartialEq)]
833 #[repr(transparent)]
834 struct PanicOnDrop<T>(T);
835
836 impl<T> Drop for PanicOnDrop<T> {
837 fn drop(&mut self) {
838 panic!("PanicOnDrop dropped");
839 }
840 }
841
842 // Since `try_transmute!` semantically moves its argument on failure,
843 // the `PanicOnDrop` is not dropped, and thus this shouldn't panic.
844 let x: Result<usize, _> = try_transmute!(PanicOnDrop(1usize));
845 assert_eq!(x, Ok(1));
846
847 // Since `try_transmute!` semantically returns ownership of its argument
848 // on failure, the `PanicOnDrop` is returned rather than dropped, and
849 // thus this shouldn't panic.
850 let y: Result<bool, _> = try_transmute!(PanicOnDrop(2u8));
851 // We have to use `map_err` instead of comparing against
852 // `Err(PanicOnDrop(2u8))` because the latter would create and then drop
853 // its `PanicOnDrop` temporary, which would cause a panic.
854 assert_eq!(y.as_ref().map_err(|p| &p.src.0), Err::<&bool, _>(&2u8));
855 mem::forget(y);
856 }
857
858 #[test]
859 fn test_try_transmute_ref() {
860 // Test that memory is transmuted with `try_transmute_ref` as expected.
861 let array_of_bools = &[false, true, false, true, false, true, false, true];
862 let array_of_arrays = &[[0, 1], [0, 1], [0, 1], [0, 1]];
863 let x: Result<&[[u8; 2]; 4], _> = try_transmute_ref!(array_of_bools);
864 assert_eq!(x, Ok(array_of_arrays));
865 let x: Result<&[bool; 8], _> = try_transmute_ref!(array_of_arrays);
866 assert_eq!(x, Ok(array_of_bools));
867
868 // Test that it's legal to transmute a reference while shrinking the
869 // lifetime.
870 {
871 let x: Result<&[[u8; 2]; 4], _> = try_transmute_ref!(array_of_bools);
872 assert_eq!(x, Ok(array_of_arrays));
873 }
874
875 // Test that `try_transmute_ref!` supports decreasing alignment.
876 let u = AU64(0);
877 let array = [0u8, 0, 0, 0, 0, 0, 0, 0];
878 let x: Result<&[u8; 8], _> = try_transmute_ref!(&u);
879 assert_eq!(x, Ok(&array));
880
881 // Test that a mutable reference can be turned into an immutable one.
882 let mut x = 0u8;
883 #[allow(clippy::useless_transmute)]
884 let y: Result<&u8, _> = try_transmute_ref!(&mut x);
885 assert_eq!(y, Ok(&0));
886 }
887
888 #[test]
889 fn test_try_transmute_mut() {
890 // Test that memory is transmuted with `try_transmute_mut` as expected.
891 let array_of_bools = &mut [false, true, false, true, false, true, false, true];
892 let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
893 let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools);
894 assert_eq!(x, Ok(array_of_arrays));
895
896 let array_of_bools = &mut [false, true, false, true, false, true, false, true];
897 let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
898 let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays);
899 assert_eq!(x, Ok(array_of_bools));
900
901 // Test that it's legal to transmute a reference while shrinking the
902 // lifetime.
903 let array_of_bools = &mut [false, true, false, true, false, true, false, true];
904 let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
905 {
906 let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools);
907 assert_eq!(x, Ok(array_of_arrays));
908 }
909
910 // Test that `try_transmute_mut!` supports decreasing alignment.
911 let u = &mut AU64(0);
912 let array = &mut [0u8, 0, 0, 0, 0, 0, 0, 0];
913 let x: Result<&mut [u8; 8], _> = try_transmute_mut!(u);
914 assert_eq!(x, Ok(array));
915
916 // Test that a mutable reference can be turned into an immutable one.
917 let mut x = 0u8;
918 #[allow(clippy::useless_transmute)]
919 let y: Result<&mut u8, _> = try_transmute_mut!(&mut x);
920 assert_eq!(y, Ok(&mut 0));
921 }
922
923 #[test]
924 fn test_transmute_mut() {
925 // Test that memory is transmuted as expected.
926 let mut array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7];
927 let mut array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]];
928 let x: &mut [[u8; 2]; 4] = transmute_mut!(&mut array_of_u8s);
929 assert_eq!(*x, array_of_arrays);
930 let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays);
931 assert_eq!(*x, array_of_u8s);
932
933 {
934 // Test that it's legal to transmute a reference while shrinking the
935 // lifetime.
936 let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays);
937 assert_eq!(*x, array_of_u8s);
938 }
939 // Test that `transmute_mut!` supports decreasing alignment.
940 let mut u = AU64(0);
941 let array = [0, 0, 0, 0, 0, 0, 0, 0];
942 let x: &[u8; 8] = transmute_mut!(&mut u);
943 assert_eq!(*x, array);
944
945 // Test that a mutable reference can be turned into an immutable one.
946 let mut x = 0u8;
947 #[allow(clippy::useless_transmute)]
948 let y: &u8 = transmute_mut!(&mut x);
949 assert_eq!(*y, 0);
950 }
951
952 #[test]
953 fn test_macros_evaluate_args_once() {
954 let mut ctr = 0;
955 #[allow(clippy::useless_transmute)]
956 let _: usize = transmute!({
957 ctr += 1;
958 0usize
959 });
960 assert_eq!(ctr, 1);
961
962 let mut ctr = 0;
963 let _: &usize = transmute_ref!({
964 ctr += 1;
965 &0usize
966 });
967 assert_eq!(ctr, 1);
968
969 let mut ctr: usize = 0;
970 let _: &mut usize = transmute_mut!({
971 ctr += 1;
972 &mut ctr
973 });
974 assert_eq!(ctr, 1);
975
976 let mut ctr = 0;
977 #[allow(clippy::useless_transmute)]
978 let _: usize = try_transmute!({
979 ctr += 1;
980 0usize
981 })
982 .unwrap();
983 assert_eq!(ctr, 1);
984 }
985
986 #[test]
987 fn test_include_value() {
988 const AS_U32: u32 = include_value!("../testdata/include_value/data");
989 assert_eq!(AS_U32, u32::from_ne_bytes([b'a', b'b', b'c', b'd']));
990 const AS_I32: i32 = include_value!("../testdata/include_value/data");
991 assert_eq!(AS_I32, i32::from_ne_bytes([b'a', b'b', b'c', b'd']));
992 }
993}