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