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