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, |
253 | /// Dst: FromBytes + IntoBytes, |
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` and that |
329 | // the type of this macro expression is `&mut U` where `U: 'u + |
330 | // Sized + FromBytes + IntoBytes`. |
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 + IntoBytes, |
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 | #[doc (hidden)] |
737 | #[macro_export ] |
738 | macro_rules! cryptocorrosion_derive_traits { |
739 | ( |
740 | #[repr($repr:ident)] |
741 | $(#[$attr:meta])* |
742 | $vis:vis struct $name:ident $(<$($tyvar:ident),*>)? |
743 | $( |
744 | ( |
745 | $($tuple_field_vis:vis $tuple_field_ty:ty),* |
746 | ); |
747 | )? |
748 | |
749 | $( |
750 | { |
751 | $($field_vis:vis $field_name:ident: $field_ty:ty,)* |
752 | } |
753 | )? |
754 | ) => { |
755 | $crate::cryptocorrosion_derive_traits!(@assert_allowed_struct_repr #[repr($repr)]); |
756 | |
757 | $(#[$attr])* |
758 | #[repr($repr)] |
759 | $vis struct $name $(<$($tyvar),*>)? |
760 | $( |
761 | ( |
762 | $($tuple_field_vis $tuple_field_ty),* |
763 | ); |
764 | )? |
765 | |
766 | $( |
767 | { |
768 | $($field_vis $field_name: $field_ty,)* |
769 | } |
770 | )? |
771 | |
772 | // SAFETY: See inline. |
773 | unsafe impl $(<$($tyvar),*>)? $crate::TryFromBytes for $name$(<$($tyvar),*>)? |
774 | where |
775 | $( |
776 | $($tuple_field_ty: $crate::FromBytes,)* |
777 | )? |
778 | |
779 | $( |
780 | $($field_ty: $crate::FromBytes,)* |
781 | )? |
782 | { |
783 | fn is_bit_valid<A>(_c: $crate::Maybe<'_, Self, A>) -> bool |
784 | where |
785 | A: $crate::pointer::invariant::Reference |
786 | { |
787 | // SAFETY: This macro only accepts `#[repr(C)]` and |
788 | // `#[repr(transparent)]` structs, and this `impl` block |
789 | // requires all field types to be `FromBytes`. Thus, all |
790 | // initialized byte sequences constitutes valid instances of |
791 | // `Self`. |
792 | true |
793 | } |
794 | |
795 | fn only_derive_is_allowed_to_implement_this_trait() {} |
796 | } |
797 | |
798 | // SAFETY: This macro only accepts `#[repr(C)]` and |
799 | // `#[repr(transparent)]` structs, and this `impl` block requires all |
800 | // field types to be `FromBytes`, which is a sub-trait of `FromZeros`. |
801 | unsafe impl $(<$($tyvar),*>)? $crate::FromZeros for $name$(<$($tyvar),*>)? |
802 | where |
803 | $( |
804 | $($tuple_field_ty: $crate::FromBytes,)* |
805 | )? |
806 | |
807 | $( |
808 | $($field_ty: $crate::FromBytes,)* |
809 | )? |
810 | { |
811 | fn only_derive_is_allowed_to_implement_this_trait() {} |
812 | } |
813 | |
814 | // SAFETY: This macro only accepts `#[repr(C)]` and |
815 | // `#[repr(transparent)]` structs, and this `impl` block requires all |
816 | // field types to be `FromBytes`. |
817 | unsafe impl $(<$($tyvar),*>)? $crate::FromBytes for $name$(<$($tyvar),*>)? |
818 | where |
819 | $( |
820 | $($tuple_field_ty: $crate::FromBytes,)* |
821 | )? |
822 | |
823 | $( |
824 | $($field_ty: $crate::FromBytes,)* |
825 | )? |
826 | { |
827 | fn only_derive_is_allowed_to_implement_this_trait() {} |
828 | } |
829 | |
830 | // SAFETY: This macro only accepts `#[repr(C)]` and |
831 | // `#[repr(transparent)]` structs, this `impl` block requires all field |
832 | // types to be `IntoBytes`, and a padding check is used to ensures that |
833 | // there are no padding bytes. |
834 | unsafe impl $(<$($tyvar),*>)? $crate::IntoBytes for $name$(<$($tyvar),*>)? |
835 | where |
836 | $( |
837 | $($tuple_field_ty: $crate::IntoBytes,)* |
838 | )? |
839 | |
840 | $( |
841 | $($field_ty: $crate::IntoBytes,)* |
842 | )? |
843 | |
844 | (): $crate::util::macro_util::PaddingFree< |
845 | Self, |
846 | { |
847 | $crate::cryptocorrosion_derive_traits!( |
848 | @struct_padding_check #[repr($repr)] |
849 | $(($($tuple_field_ty),*))? |
850 | $({$($field_ty),*})? |
851 | ) |
852 | }, |
853 | >, |
854 | { |
855 | fn only_derive_is_allowed_to_implement_this_trait() {} |
856 | } |
857 | |
858 | // SAFETY: This macro only accepts `#[repr(C)]` and |
859 | // `#[repr(transparent)]` structs, and this `impl` block requires all |
860 | // field types to be `Immutable`. |
861 | unsafe impl $(<$($tyvar),*>)? $crate::Immutable for $name$(<$($tyvar),*>)? |
862 | where |
863 | $( |
864 | $($tuple_field_ty: $crate::Immutable,)* |
865 | )? |
866 | |
867 | $( |
868 | $($field_ty: $crate::Immutable,)* |
869 | )? |
870 | { |
871 | fn only_derive_is_allowed_to_implement_this_trait() {} |
872 | } |
873 | }; |
874 | (@assert_allowed_struct_repr #[repr(transparent)]) => {}; |
875 | (@assert_allowed_struct_repr #[repr(C)]) => {}; |
876 | (@assert_allowed_struct_repr #[$_attr:meta]) => { |
877 | compile_error!("repr must be `#[repr(transparent)]` or `#[repr(C)]`" ); |
878 | }; |
879 | ( |
880 | @struct_padding_check #[repr(transparent)] |
881 | $(($($tuple_field_ty:ty),*))? |
882 | $({$($field_ty:ty),*})? |
883 | ) => { |
884 | // SAFETY: `#[repr(transparent)]` structs cannot have the same layout as |
885 | // their single non-zero-sized field, and so cannot have any padding |
886 | // outside of that field. |
887 | false |
888 | }; |
889 | ( |
890 | @struct_padding_check #[repr(C)] |
891 | $(($($tuple_field_ty:ty),*))? |
892 | $({$($field_ty:ty),*})? |
893 | ) => { |
894 | $crate::struct_has_padding!( |
895 | Self, |
896 | [ |
897 | $($($tuple_field_ty),*)? |
898 | $($($field_ty),*)? |
899 | ] |
900 | ) |
901 | }; |
902 | ( |
903 | #[repr(C)] |
904 | $(#[$attr:meta])* |
905 | $vis:vis union $name:ident { |
906 | $( |
907 | $field_name:ident: $field_ty:ty, |
908 | )* |
909 | } |
910 | ) => { |
911 | $(#[$attr])* |
912 | #[repr(C)] |
913 | $vis union $name { |
914 | $( |
915 | $field_name: $field_ty, |
916 | )* |
917 | } |
918 | |
919 | // SAFETY: See inline. |
920 | unsafe impl $crate::TryFromBytes for $name |
921 | where |
922 | $( |
923 | $field_ty: $crate::FromBytes, |
924 | )* |
925 | { |
926 | fn is_bit_valid<A>(_c: $crate::Maybe<'_, Self, A>) -> bool |
927 | where |
928 | A: $crate::pointer::invariant::Reference |
929 | { |
930 | // SAFETY: This macro only accepts `#[repr(C)]` unions, and this |
931 | // `impl` block requires all field types to be `FromBytes`. |
932 | // Thus, all initialized byte sequences constitutes valid |
933 | // instances of `Self`. |
934 | true |
935 | } |
936 | |
937 | fn only_derive_is_allowed_to_implement_this_trait() {} |
938 | } |
939 | |
940 | // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl` |
941 | // block requires all field types to be `FromBytes`, which is a |
942 | // sub-trait of `FromZeros`. |
943 | unsafe impl $crate::FromZeros for $name |
944 | where |
945 | $( |
946 | $field_ty: $crate::FromBytes, |
947 | )* |
948 | { |
949 | fn only_derive_is_allowed_to_implement_this_trait() {} |
950 | } |
951 | |
952 | // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl` |
953 | // block requires all field types to be `FromBytes`. |
954 | unsafe impl $crate::FromBytes for $name |
955 | where |
956 | $( |
957 | $field_ty: $crate::FromBytes, |
958 | )* |
959 | { |
960 | fn only_derive_is_allowed_to_implement_this_trait() {} |
961 | } |
962 | |
963 | // SAFETY: This macro only accepts `#[repr(C)]` unions, this `impl` |
964 | // block requires all field types to be `IntoBytes`, and a padding check |
965 | // is used to ensures that there are no padding bytes before or after |
966 | // any field. |
967 | unsafe impl $crate::IntoBytes for $name |
968 | where |
969 | $( |
970 | $field_ty: $crate::IntoBytes, |
971 | )* |
972 | (): $crate::util::macro_util::PaddingFree< |
973 | Self, |
974 | { |
975 | $crate::union_has_padding!( |
976 | Self, |
977 | [$($field_ty),*] |
978 | ) |
979 | }, |
980 | >, |
981 | { |
982 | fn only_derive_is_allowed_to_implement_this_trait() {} |
983 | } |
984 | |
985 | // SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl` |
986 | // block requires all field types to be `Immutable`. |
987 | unsafe impl $crate::Immutable for $name |
988 | where |
989 | $( |
990 | $field_ty: $crate::Immutable, |
991 | )* |
992 | { |
993 | fn only_derive_is_allowed_to_implement_this_trait() {} |
994 | } |
995 | }; |
996 | } |
997 | |
998 | #[cfg (test)] |
999 | mod tests { |
1000 | use crate::util::testutil::*; |
1001 | use crate::*; |
1002 | |
1003 | #[test ] |
1004 | fn test_transmute() { |
1005 | // Test that memory is transmuted as expected. |
1006 | let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; |
1007 | let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; |
1008 | let x: [[u8; 2]; 4] = transmute!(array_of_u8s); |
1009 | assert_eq!(x, array_of_arrays); |
1010 | let x: [u8; 8] = transmute!(array_of_arrays); |
1011 | assert_eq!(x, array_of_u8s); |
1012 | |
1013 | // Test that the source expression's value is forgotten rather than |
1014 | // dropped. |
1015 | #[derive (IntoBytes)] |
1016 | #[repr (transparent)] |
1017 | struct PanicOnDrop(()); |
1018 | impl Drop for PanicOnDrop { |
1019 | fn drop(&mut self) { |
1020 | panic!("PanicOnDrop::drop" ); |
1021 | } |
1022 | } |
1023 | #[allow (clippy::let_unit_value)] |
1024 | let _: () = transmute!(PanicOnDrop(())); |
1025 | |
1026 | // Test that `transmute!` is legal in a const context. |
1027 | const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7]; |
1028 | const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]]; |
1029 | const X: [[u8; 2]; 4] = transmute!(ARRAY_OF_U8S); |
1030 | assert_eq!(X, ARRAY_OF_ARRAYS); |
1031 | |
1032 | // Test that `transmute!` works with `!Immutable` types. |
1033 | let x: usize = transmute!(UnsafeCell::new(1usize)); |
1034 | assert_eq!(x, 1); |
1035 | let x: UnsafeCell<usize> = transmute!(1usize); |
1036 | assert_eq!(x.into_inner(), 1); |
1037 | let x: UnsafeCell<isize> = transmute!(UnsafeCell::new(1usize)); |
1038 | assert_eq!(x.into_inner(), 1); |
1039 | } |
1040 | |
1041 | #[test ] |
1042 | fn test_transmute_ref() { |
1043 | // Test that memory is transmuted as expected. |
1044 | let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; |
1045 | let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; |
1046 | let x: &[[u8; 2]; 4] = transmute_ref!(&array_of_u8s); |
1047 | assert_eq!(*x, array_of_arrays); |
1048 | let x: &[u8; 8] = transmute_ref!(&array_of_arrays); |
1049 | assert_eq!(*x, array_of_u8s); |
1050 | |
1051 | // Test that `transmute_ref!` is legal in a const context. |
1052 | const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7]; |
1053 | const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]]; |
1054 | #[allow (clippy::redundant_static_lifetimes)] |
1055 | const X: &'static [[u8; 2]; 4] = transmute_ref!(&ARRAY_OF_U8S); |
1056 | assert_eq!(*X, ARRAY_OF_ARRAYS); |
1057 | |
1058 | // Test that it's legal to transmute a reference while shrinking the |
1059 | // lifetime (note that `X` has the lifetime `'static`). |
1060 | let x: &[u8; 8] = transmute_ref!(X); |
1061 | assert_eq!(*x, ARRAY_OF_U8S); |
1062 | |
1063 | // Test that `transmute_ref!` supports decreasing alignment. |
1064 | let u = AU64(0); |
1065 | let array = [0, 0, 0, 0, 0, 0, 0, 0]; |
1066 | let x: &[u8; 8] = transmute_ref!(&u); |
1067 | assert_eq!(*x, array); |
1068 | |
1069 | // Test that a mutable reference can be turned into an immutable one. |
1070 | let mut x = 0u8; |
1071 | #[allow (clippy::useless_transmute)] |
1072 | let y: &u8 = transmute_ref!(&mut x); |
1073 | assert_eq!(*y, 0); |
1074 | } |
1075 | |
1076 | #[test ] |
1077 | fn test_try_transmute() { |
1078 | // Test that memory is transmuted with `try_transmute` as expected. |
1079 | let array_of_bools = [false, true, false, true, false, true, false, true]; |
1080 | let array_of_arrays = [[0, 1], [0, 1], [0, 1], [0, 1]]; |
1081 | let x: Result<[[u8; 2]; 4], _> = try_transmute!(array_of_bools); |
1082 | assert_eq!(x, Ok(array_of_arrays)); |
1083 | let x: Result<[bool; 8], _> = try_transmute!(array_of_arrays); |
1084 | assert_eq!(x, Ok(array_of_bools)); |
1085 | |
1086 | // Test that `try_transmute!` works with `!Immutable` types. |
1087 | let x: Result<usize, _> = try_transmute!(UnsafeCell::new(1usize)); |
1088 | assert_eq!(x.unwrap(), 1); |
1089 | let x: Result<UnsafeCell<usize>, _> = try_transmute!(1usize); |
1090 | assert_eq!(x.unwrap().into_inner(), 1); |
1091 | let x: Result<UnsafeCell<isize>, _> = try_transmute!(UnsafeCell::new(1usize)); |
1092 | assert_eq!(x.unwrap().into_inner(), 1); |
1093 | |
1094 | #[derive (FromBytes, IntoBytes, Debug, PartialEq)] |
1095 | #[repr (transparent)] |
1096 | struct PanicOnDrop<T>(T); |
1097 | |
1098 | impl<T> Drop for PanicOnDrop<T> { |
1099 | fn drop(&mut self) { |
1100 | panic!("PanicOnDrop dropped" ); |
1101 | } |
1102 | } |
1103 | |
1104 | // Since `try_transmute!` semantically moves its argument on failure, |
1105 | // the `PanicOnDrop` is not dropped, and thus this shouldn't panic. |
1106 | let x: Result<usize, _> = try_transmute!(PanicOnDrop(1usize)); |
1107 | assert_eq!(x, Ok(1)); |
1108 | |
1109 | // Since `try_transmute!` semantically returns ownership of its argument |
1110 | // on failure, the `PanicOnDrop` is returned rather than dropped, and |
1111 | // thus this shouldn't panic. |
1112 | let y: Result<bool, _> = try_transmute!(PanicOnDrop(2u8)); |
1113 | // We have to use `map_err` instead of comparing against |
1114 | // `Err(PanicOnDrop(2u8))` because the latter would create and then drop |
1115 | // its `PanicOnDrop` temporary, which would cause a panic. |
1116 | assert_eq!(y.as_ref().map_err(|p| &p.src.0), Err::<&bool, _>(&2u8)); |
1117 | mem::forget(y); |
1118 | } |
1119 | |
1120 | #[test ] |
1121 | fn test_try_transmute_ref() { |
1122 | // Test that memory is transmuted with `try_transmute_ref` as expected. |
1123 | let array_of_bools = &[false, true, false, true, false, true, false, true]; |
1124 | let array_of_arrays = &[[0, 1], [0, 1], [0, 1], [0, 1]]; |
1125 | let x: Result<&[[u8; 2]; 4], _> = try_transmute_ref!(array_of_bools); |
1126 | assert_eq!(x, Ok(array_of_arrays)); |
1127 | let x: Result<&[bool; 8], _> = try_transmute_ref!(array_of_arrays); |
1128 | assert_eq!(x, Ok(array_of_bools)); |
1129 | |
1130 | // Test that it's legal to transmute a reference while shrinking the |
1131 | // lifetime. |
1132 | { |
1133 | let x: Result<&[[u8; 2]; 4], _> = try_transmute_ref!(array_of_bools); |
1134 | assert_eq!(x, Ok(array_of_arrays)); |
1135 | } |
1136 | |
1137 | // Test that `try_transmute_ref!` supports decreasing alignment. |
1138 | let u = AU64(0); |
1139 | let array = [0u8, 0, 0, 0, 0, 0, 0, 0]; |
1140 | let x: Result<&[u8; 8], _> = try_transmute_ref!(&u); |
1141 | assert_eq!(x, Ok(&array)); |
1142 | |
1143 | // Test that a mutable reference can be turned into an immutable one. |
1144 | let mut x = 0u8; |
1145 | #[allow (clippy::useless_transmute)] |
1146 | let y: Result<&u8, _> = try_transmute_ref!(&mut x); |
1147 | assert_eq!(y, Ok(&0)); |
1148 | } |
1149 | |
1150 | #[test ] |
1151 | fn test_try_transmute_mut() { |
1152 | // Test that memory is transmuted with `try_transmute_mut` as expected. |
1153 | let array_of_u8s = &mut [0u8, 1, 0, 1, 0, 1, 0, 1]; |
1154 | let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]]; |
1155 | let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_u8s); |
1156 | assert_eq!(x, Ok(array_of_arrays)); |
1157 | |
1158 | let array_of_bools = &mut [false, true, false, true, false, true, false, true]; |
1159 | let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]]; |
1160 | let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays); |
1161 | assert_eq!(x, Ok(array_of_bools)); |
1162 | |
1163 | // Test that it's legal to transmute a reference while shrinking the |
1164 | // lifetime. |
1165 | let array_of_bools = &mut [false, true, false, true, false, true, false, true]; |
1166 | let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]]; |
1167 | { |
1168 | let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays); |
1169 | assert_eq!(x, Ok(array_of_bools)); |
1170 | } |
1171 | |
1172 | // Test that `try_transmute_mut!` supports decreasing alignment. |
1173 | let u = &mut AU64(0); |
1174 | let array = &mut [0u8, 0, 0, 0, 0, 0, 0, 0]; |
1175 | let x: Result<&mut [u8; 8], _> = try_transmute_mut!(u); |
1176 | assert_eq!(x, Ok(array)); |
1177 | |
1178 | // Test that a mutable reference can be turned into an immutable one. |
1179 | let mut x = 0u8; |
1180 | #[allow (clippy::useless_transmute)] |
1181 | let y: Result<&mut u8, _> = try_transmute_mut!(&mut x); |
1182 | assert_eq!(y, Ok(&mut 0)); |
1183 | } |
1184 | |
1185 | #[test ] |
1186 | fn test_transmute_mut() { |
1187 | // Test that memory is transmuted as expected. |
1188 | let mut array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; |
1189 | let mut array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; |
1190 | let x: &mut [[u8; 2]; 4] = transmute_mut!(&mut array_of_u8s); |
1191 | assert_eq!(*x, array_of_arrays); |
1192 | let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays); |
1193 | assert_eq!(*x, array_of_u8s); |
1194 | |
1195 | { |
1196 | // Test that it's legal to transmute a reference while shrinking the |
1197 | // lifetime. |
1198 | let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays); |
1199 | assert_eq!(*x, array_of_u8s); |
1200 | } |
1201 | // Test that `transmute_mut!` supports decreasing alignment. |
1202 | let mut u = AU64(0); |
1203 | let array = [0, 0, 0, 0, 0, 0, 0, 0]; |
1204 | let x: &[u8; 8] = transmute_mut!(&mut u); |
1205 | assert_eq!(*x, array); |
1206 | |
1207 | // Test that a mutable reference can be turned into an immutable one. |
1208 | let mut x = 0u8; |
1209 | #[allow (clippy::useless_transmute)] |
1210 | let y: &u8 = transmute_mut!(&mut x); |
1211 | assert_eq!(*y, 0); |
1212 | } |
1213 | |
1214 | #[test ] |
1215 | fn test_macros_evaluate_args_once() { |
1216 | let mut ctr = 0; |
1217 | #[allow (clippy::useless_transmute)] |
1218 | let _: usize = transmute!({ |
1219 | ctr += 1; |
1220 | 0usize |
1221 | }); |
1222 | assert_eq!(ctr, 1); |
1223 | |
1224 | let mut ctr = 0; |
1225 | let _: &usize = transmute_ref!({ |
1226 | ctr += 1; |
1227 | &0usize |
1228 | }); |
1229 | assert_eq!(ctr, 1); |
1230 | |
1231 | let mut ctr: usize = 0; |
1232 | let _: &mut usize = transmute_mut!({ |
1233 | ctr += 1; |
1234 | &mut ctr |
1235 | }); |
1236 | assert_eq!(ctr, 1); |
1237 | |
1238 | let mut ctr = 0; |
1239 | #[allow (clippy::useless_transmute)] |
1240 | let _: usize = try_transmute!({ |
1241 | ctr += 1; |
1242 | 0usize |
1243 | }) |
1244 | .unwrap(); |
1245 | assert_eq!(ctr, 1); |
1246 | } |
1247 | |
1248 | #[test ] |
1249 | fn test_include_value() { |
1250 | const AS_U32: u32 = include_value!("../testdata/include_value/data" ); |
1251 | assert_eq!(AS_U32, u32::from_ne_bytes([b'a' , b'b' , b'c' , b'd' ])); |
1252 | const AS_I32: i32 = include_value!("../testdata/include_value/data" ); |
1253 | assert_eq!(AS_I32, i32::from_ne_bytes([b'a' , b'b' , b'c' , b'd' ])); |
1254 | } |
1255 | |
1256 | #[test ] |
1257 | #[allow (non_camel_case_types, unreachable_pub, dead_code)] |
1258 | fn test_cryptocorrosion_derive_traits() { |
1259 | // Test the set of invocations added in |
1260 | // https://github.com/cryptocorrosion/cryptocorrosion/pull/85 |
1261 | |
1262 | fn assert_impls<T: FromBytes + IntoBytes + Immutable>() {} |
1263 | |
1264 | cryptocorrosion_derive_traits! { |
1265 | #[repr(C)] |
1266 | #[derive(Clone, Copy)] |
1267 | pub union vec128_storage { |
1268 | d: [u32; 4], |
1269 | q: [u64; 2], |
1270 | } |
1271 | } |
1272 | |
1273 | assert_impls::<vec128_storage>(); |
1274 | |
1275 | cryptocorrosion_derive_traits! { |
1276 | #[repr(transparent)] |
1277 | #[derive(Copy, Clone, Debug, PartialEq)] |
1278 | pub struct u32x4_generic([u32; 4]); |
1279 | } |
1280 | |
1281 | assert_impls::<u32x4_generic>(); |
1282 | |
1283 | cryptocorrosion_derive_traits! { |
1284 | #[repr(transparent)] |
1285 | #[derive(Copy, Clone, Debug, PartialEq)] |
1286 | pub struct u64x2_generic([u64; 2]); |
1287 | } |
1288 | |
1289 | assert_impls::<u64x2_generic>(); |
1290 | |
1291 | cryptocorrosion_derive_traits! { |
1292 | #[repr(transparent)] |
1293 | #[derive(Copy, Clone, Debug, PartialEq)] |
1294 | pub struct u128x1_generic([u128; 1]); |
1295 | } |
1296 | |
1297 | assert_impls::<u128x1_generic>(); |
1298 | |
1299 | cryptocorrosion_derive_traits! { |
1300 | #[repr(transparent)] |
1301 | #[derive(Copy, Clone, Default)] |
1302 | #[allow(non_camel_case_types)] |
1303 | pub struct x2<W, G>(pub [W; 2], PhantomData<G>); |
1304 | } |
1305 | |
1306 | enum NotZerocopy {} |
1307 | assert_impls::<x2<(), NotZerocopy>>(); |
1308 | |
1309 | cryptocorrosion_derive_traits! { |
1310 | #[repr(transparent)] |
1311 | #[derive(Copy, Clone, Default)] |
1312 | #[allow(non_camel_case_types)] |
1313 | pub struct x4<W>(pub [W; 4]); |
1314 | } |
1315 | |
1316 | assert_impls::<x4<()>>(); |
1317 | |
1318 | #[cfg (feature = "simd" )] |
1319 | #[cfg (any(target_arch = "x86" , target_arch = "x86_64" ))] |
1320 | { |
1321 | #[cfg (target_arch = "x86" )] |
1322 | use core::arch::x86::{__m128i, __m256i}; |
1323 | #[cfg (target_arch = "x86_64" )] |
1324 | use core::arch::x86_64::{__m128i, __m256i}; |
1325 | |
1326 | cryptocorrosion_derive_traits! { |
1327 | #[repr(C)] |
1328 | #[derive(Copy, Clone)] |
1329 | pub struct X4(__m128i, __m128i, __m128i, __m128i); |
1330 | } |
1331 | |
1332 | assert_impls::<X4>(); |
1333 | |
1334 | cryptocorrosion_derive_traits! { |
1335 | #[repr(C)] |
1336 | /// Generic wrapper for unparameterized storage of any of the possible impls. |
1337 | /// Converting into and out of this type should be essentially free, although it may be more |
1338 | /// aligned than a particular impl requires. |
1339 | #[allow(non_camel_case_types)] |
1340 | #[derive(Copy, Clone)] |
1341 | pub union vec128_storage { |
1342 | u32x4: [u32; 4], |
1343 | u64x2: [u64; 2], |
1344 | u128x1: [u128; 1], |
1345 | sse2: __m128i, |
1346 | } |
1347 | } |
1348 | |
1349 | assert_impls::<vec128_storage>(); |
1350 | |
1351 | cryptocorrosion_derive_traits! { |
1352 | #[repr(transparent)] |
1353 | #[allow(non_camel_case_types)] |
1354 | #[derive(Copy, Clone)] |
1355 | pub struct vec<S3, S4, NI> { |
1356 | x: __m128i, |
1357 | s3: PhantomData<S3>, |
1358 | s4: PhantomData<S4>, |
1359 | ni: PhantomData<NI>, |
1360 | } |
1361 | } |
1362 | |
1363 | assert_impls::<vec<NotZerocopy, NotZerocopy, NotZerocopy>>(); |
1364 | |
1365 | cryptocorrosion_derive_traits! { |
1366 | #[repr(transparent)] |
1367 | #[derive(Copy, Clone)] |
1368 | pub struct u32x4x2_avx2<NI> { |
1369 | x: __m256i, |
1370 | ni: PhantomData<NI>, |
1371 | } |
1372 | } |
1373 | |
1374 | assert_impls::<u32x4x2_avx2<NotZerocopy>>(); |
1375 | } |
1376 | |
1377 | // Make sure that our derive works for `#[repr(C)]` structs even though |
1378 | // cryptocorrosion doesn't currently have any. |
1379 | cryptocorrosion_derive_traits! { |
1380 | #[repr(C)] |
1381 | #[derive(Copy, Clone, Debug, PartialEq)] |
1382 | pub struct ReprC(u8, u8, u16); |
1383 | } |
1384 | } |
1385 | } |
1386 | |