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