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 ] |
53 | macro_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 ] |
168 | macro_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 ] |
316 | macro_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 ] |
440 | macro_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 ] |
536 | macro_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: FromBytes + 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 ] |
646 | macro_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 ] |
730 | macro_rules! include_value { |
731 | ($file:expr $(,)?) => { |
732 | $crate::transmute!(*::core::include_bytes!($file)) |
733 | }; |
734 | } |
735 | |
736 | #[cfg (test)] |
737 | mod 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_u8s = &mut [0u8, 1, 0, 1, 0, 1, 0, 1]; |
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_u8s); |
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 [bool; 8], _> = try_transmute_mut!(array_of_arrays); |
907 | assert_eq!(x, Ok(array_of_bools)); |
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 | } |
994 | |