/// Safely transmutes a value of one type to a value of another type of the same /// size. /// /// This macro behaves like an invocation of this function: /// /// ```ignore /// const fn transmute<Src, Dst>(src: Src) -> Dst /// where /// Src: IntoBytes, /// Dst: FromBytes, /// size_of::<Src>() == size_of::<Dst>(), /// { /// # /* /// ... /// # */ /// } /// ``` /// /// However, unlike a function, this macro can only be invoked when the types of /// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are /// inferred from the calling context; they cannot be explicitly specified in /// the macro invocation. /// /// Note that the `Src` produced by the expression `$e` will *not* be dropped. /// Semantically, its bits will be copied into a new value of type `Dst`, the /// original `Src` will be forgotten, and the value of type `Dst` will be /// returned. /// /// # `#![allow(shrink)]` /// /// If `#![allow(shrink)]` is provided, `transmute!` additionally supports /// transmutations that shrink the size of the value; e.g.: /// /// ``` /// # use zerocopy::transmute; /// let u: u32 = transmute!(#![allow(shrink)] 0u64); /// assert_eq!(u, 0u32); /// ``` /// /// # Examples /// /// ``` /// # use zerocopy::transmute; /// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; /// /// let two_dimensional: [[u8; 4]; 2] = transmute!(one_dimensional); /// /// assert_eq!(two_dimensional, [[0, 1, 2, 3], [4, 5, 6, 7]]); /// ``` /// /// # Use in `const` contexts /// /// This macro can be invoked in `const` contexts. #[macro_export]
macro_rules! transmute { // NOTE: This must be a macro (rather than a function with trait bounds) // because there's no way, in a generic context, to enforce that two types // have the same size. `core::mem::transmute` uses compiler magic to enforce // this so long as the types are concrete.
(#![allow(shrink)] $e:expr) => {{ letmut e = $e; iffalse { // This branch, though never taken, ensures that the type of `e` is // `IntoBytes` and that the type of the outer macro invocation // expression is `FromBytes`.
fn transmute<Src, Dst>(src: Src) -> Dst where
Src: $crate::IntoBytes,
Dst: $crate::FromBytes,
{ let _ = src; loop {}
} loop {} #[allow(unreachable_code)]
transmute(e)
} else { use $crate::util::macro_util::core_reexport::mem::ManuallyDrop;
// NOTE: `repr(packed)` is important! It ensures that the size of // `Transmute` won't be rounded up to accommodate `Src`'s or `Dst`'s // alignment, which would break the size comparison logic below. // // As an example of why this is problematic, consider `Src = [u8; // 5]`, `Dst = u32`. The total size of `Transmute<Src, Dst>` would // be 8, and so we would reject a `[u8; 5]` to `u32` transmute as // being size-increasing, which it isn't. #[repr(C, packed)]
union Transmute<Src, Dst> {
src: ManuallyDrop<Src>,
dst: ManuallyDrop<Dst>,
}
// SAFETY: `Transmute` is a `reper(C)` union whose `src` field has // type `ManuallyDrop<Src>`. Thus, the `src` field starts at byte // offset 0 within `Transmute` [1]. `ManuallyDrop<T>` has the same // layout and bit validity as `T`, so it is sound to transmute `Src` // to `Transmute`. // // [1] https://doc.rust-lang.org/1.85.0/reference/type-layout.html#reprc-unions // // [2] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html: // // `ManuallyDrop<T>` is guaranteed to have the same layout and bit // validity as `T` let u: Transmute<_, _> = unsafe { // Clippy: We can't annotate the types; this macro is designed // to infer the types from the calling context. #[allow(clippy::missing_transmute_annotations)]
$crate::util::macro_util::core_reexport::mem::transmute(e)
};
iffalse { // SAFETY: This code is never executed.
e = ManuallyDrop::into_inner(unsafe { u.src }); // Suppress the `unused_assignments` lint on the previous line. let _ = e; loop {}
} else { // SAFETY: Per the safety comment on `let u` above, the `dst` // field in `Transmute` starts at byte offset 0, and has the // same layout and bit validity as `Dst`. // // Transmuting `Src` to `Transmute<Src, Dst>` above using // `core::mem::transmute` ensures that `size_of::<Src>() == // size_of::<Transmute<Src, Dst>>()`. A `#[repr(C, packed)]` // union has the maximum size of all of its fields [1], so this // is equivalent to `size_of::<Src>() >= size_of::<Dst>()`. // // The outer `if`'s `false` branch ensures that `Src: IntoBytes` // and `Dst: FromBytes`. This, combined with the size bound, // ensures that this transmute is sound. // // [1] Per https://doc.rust-lang.org/1.85.0/reference/type-layout.html#reprc-unions: // // The union will have a size of the maximum size of all of // its fields rounded to its alignment let dst = unsafe { u.dst };
$crate::util::macro_util::must_use(ManuallyDrop::into_inner(dst))
}
}
}};
($e:expr) => {{ let e = $e; iffalse { // This branch, though never taken, ensures that the type of `e` is // `IntoBytes` and that the type of the outer macro invocation // expression is `FromBytes`.
fn transmute<Src, Dst>(src: Src) -> Dst where
Src: $crate::IntoBytes,
Dst: $crate::FromBytes,
{ let _ = src; loop {}
} loop {} #[allow(unreachable_code)]
transmute(e)
} else { // SAFETY: `core::mem::transmute` ensures that the type of `e` and // the type of this macro invocation expression have the same size. // We know this transmute is safe thanks to the `IntoBytes` and // `FromBytes` bounds enforced by the `false` branch. let u = unsafe { // Clippy: We can't annotate the types; this macro is designed // to infer the types from the calling context. #[allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
$crate::util::macro_util::core_reexport::mem::transmute(e)
};
$crate::util::macro_util::must_use(u)
}
}};
}
/// Safely transmutes a mutable or immutable reference of one type to an /// immutable reference of another type of the same size and compatible /// alignment. /// /// This macro behaves like an invocation of this function: /// /// ```ignore /// fn transmute_ref<'src, 'dst, Src, Dst>(src: &'src Src) -> &'dst Dst /// where /// 'src: 'dst, /// Src: IntoBytes + Immutable + ?Sized, /// Dst: FromBytes + Immutable + ?Sized, /// align_of::<Src>() >= align_of::<Dst>(), /// size_compatible::<Src, Dst>(), /// { /// # /* /// ... /// # */ /// } /// ``` /// /// The types `Src` and `Dst` are inferred from the calling context; they cannot /// be explicitly specified in the macro invocation. /// /// # Size compatibility /// /// `transmute_ref!` supports transmuting between `Sized` types or between /// unsized (i.e., `?Sized`) types. It supports any transmutation that preserves /// the number of bytes of the referent, even if doing so requires updating the /// metadata stored in an unsized "fat" reference: /// /// ``` /// # use zerocopy::transmute_ref; /// # use core::mem::size_of_val; // Not in the prelude on our MSRV /// let src: &[[u8; 2]] = &[[0, 1], [2, 3]][..]; /// let dst: &[u8] = transmute_ref!(src); /// /// assert_eq!(src.len(), 2); /// assert_eq!(dst.len(), 4); /// assert_eq!(dst, [0, 1, 2, 3]); /// assert_eq!(size_of_val(src), size_of_val(dst)); /// ``` /// /// # Errors /// /// Violations of the alignment and size compatibility checks are detected /// *after* the compiler performs monomorphization. This has two important /// consequences. /// /// First, it means that generic code will *never* fail these conditions: /// /// ``` /// # use zerocopy::{transmute_ref, FromBytes, IntoBytes, Immutable}; /// fn transmute_ref<Src, Dst>(src: &Src) -> &Dst /// where /// Src: IntoBytes + Immutable, /// Dst: FromBytes + Immutable, /// { /// transmute_ref!(src) /// } /// ``` /// /// Instead, failures will only be detected once generic code is instantiated /// with concrete types: /// /// ```compile_fail,E0080 /// # use zerocopy::{transmute_ref, FromBytes, IntoBytes, Immutable}; /// # /// # fn transmute_ref<Src, Dst>(src: &Src) -> &Dst /// # where /// # Src: IntoBytes + Immutable, /// # Dst: FromBytes + Immutable, /// # { /// # transmute_ref!(src) /// # } /// let src: &u16 = &0; /// let dst: &u8 = transmute_ref(src); /// ``` /// /// Second, the fact that violations are detected after monomorphization means /// that `cargo check` will usually not detect errors, even when types are /// concrete. Instead, `cargo build` must be used to detect such errors. /// /// # Examples /// /// Transmuting between `Sized` types: /// /// ``` /// # use zerocopy::transmute_ref; /// let one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; /// /// let two_dimensional: &[[u8; 4]; 2] = transmute_ref!(&one_dimensional); /// /// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]); /// ``` /// /// Transmuting between unsized types: /// /// ``` /// # use {zerocopy::*, zerocopy_derive::*}; /// # type u16 = zerocopy::byteorder::native_endian::U16; /// # type u32 = zerocopy::byteorder::native_endian::U32; /// #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)] /// #[repr(C)] /// struct SliceDst<T, U> { /// t: T, /// u: [U], /// } /// /// type Src = SliceDst<u32, u16>; /// type Dst = SliceDst<u16, u8>; /// /// let src = Src::ref_from_bytes(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); /// let dst: &Dst = transmute_ref!(src); /// /// assert_eq!(src.t.as_bytes(), [0, 1, 2, 3]); /// assert_eq!(src.u.len(), 2); /// assert_eq!(src.u.as_bytes(), [4, 5, 6, 7]); /// /// assert_eq!(dst.t.as_bytes(), [0, 1]); /// assert_eq!(dst.u, [2, 3, 4, 5, 6, 7]); /// ``` /// /// # Use in `const` contexts /// /// This macro can be invoked in `const` contexts only when `Src: Sized` and /// `Dst: Sized`. #[macro_export]
macro_rules! transmute_ref {
($e:expr) => {{ // NOTE: This must be a macro (rather than a function with trait bounds) // because there's no way, in a generic context, to enforce that two // types have the same size or alignment.
// Ensure that the source type is a reference or a mutable reference // (note that mutable references are implicitly reborrowed here). let e: &_ = $e;
#[allow(unused, clippy::diverging_sub_expression)] iffalse { // This branch, though never taken, ensures that the type of `e` is // `&T` where `T: IntoBytes + Immutable`, and that the type of this // macro expression is `&U` where `U: FromBytes + Immutable`.
let _ = AssertSrcIsIntoBytes(e); let _ = AssertSrcIsImmutable(e);
iftrue { #[allow(unused, unreachable_code)] let u = AssertDstIsFromBytes(loop {});
u.0
} else { #[allow(unused, unreachable_code)] let u = AssertDstIsImmutable(loop {});
u.0
}
} else { use $crate::util::macro_util::TransmuteRefDst; let t = $crate::util::macro_util::Wrap::new(e); // SAFETY: The `if false` branch ensures that: // - `Src: IntoBytes + Immutable` // - `Dst: FromBytes + Immutable` unsafe {
t.transmute_ref()
}
}
}}
}
/// Safely transmutes a mutable reference of one type to a mutable reference of /// another type of the same size and compatible alignment. /// /// This macro behaves like an invocation of this function: /// /// ```ignore /// const fn transmute_mut<'src, 'dst, Src, Dst>(src: &'src mut Src) -> &'dst mut Dst /// where /// 'src: 'dst, /// Src: FromBytes + IntoBytes, /// Dst: FromBytes + IntoBytes, /// align_of::<Src>() >= align_of::<Dst>(), /// size_compatible::<Src, Dst>(), /// { /// # /* /// ... /// # */ /// } /// ``` /// /// The types `Src` and `Dst` are inferred from the calling context; they cannot /// be explicitly specified in the macro invocation. /// /// # Size compatibility /// /// `transmute_mut!` supports transmuting between `Sized` types or between /// unsized (i.e., `?Sized`) types. It supports any transmutation that preserves /// the number of bytes of the referent, even if doing so requires updating the /// metadata stored in an unsized "fat" reference: /// /// ``` /// # use zerocopy::transmute_mut; /// # use core::mem::size_of_val; // Not in the prelude on our MSRV /// let src: &mut [[u8; 2]] = &mut [[0, 1], [2, 3]][..]; /// let dst: &mut [u8] = transmute_mut!(src); /// /// assert_eq!(dst.len(), 4); /// assert_eq!(dst, [0, 1, 2, 3]); /// let dst_size = size_of_val(dst); /// assert_eq!(src.len(), 2); /// assert_eq!(size_of_val(src), dst_size); /// ``` /// /// # Errors /// /// Violations of the alignment and size compatibility checks are detected /// *after* the compiler performs monomorphization. This has two important /// consequences. /// /// First, it means that generic code will *never* fail these conditions: /// /// ``` /// # use zerocopy::{transmute_mut, FromBytes, IntoBytes, Immutable}; /// fn transmute_mut<Src, Dst>(src: &mut Src) -> &mut Dst /// where /// Src: FromBytes + IntoBytes, /// Dst: FromBytes + IntoBytes, /// { /// transmute_mut!(src) /// } /// ``` /// /// Instead, failures will only be detected once generic code is instantiated /// with concrete types: /// /// ```compile_fail,E0080 /// # use zerocopy::{transmute_mut, FromBytes, IntoBytes, Immutable}; /// # /// # fn transmute_mut<Src, Dst>(src: &mut Src) -> &mut Dst /// # where /// # Src: FromBytes + IntoBytes, /// # Dst: FromBytes + IntoBytes, /// # { /// # transmute_mut!(src) /// # } /// let src: &mut u16 = &mut 0; /// let dst: &mut u8 = transmute_mut(src); /// ``` /// /// Second, the fact that violations are detected after monomorphization means /// that `cargo check` will usually not detect errors, even when types are /// concrete. Instead, `cargo build` must be used to detect such errors. /// /// /// # Examples /// /// Transmuting between `Sized` types: /// /// ``` /// # use zerocopy::transmute_mut; /// let mut one_dimensional: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; /// /// let two_dimensional: &mut [[u8; 4]; 2] = transmute_mut!(&mut one_dimensional); /// /// assert_eq!(two_dimensional, &[[0, 1, 2, 3], [4, 5, 6, 7]]); /// /// two_dimensional.reverse(); /// /// assert_eq!(one_dimensional, [4, 5, 6, 7, 0, 1, 2, 3]); /// ``` /// /// Transmuting between unsized types: /// /// ``` /// # use {zerocopy::*, zerocopy_derive::*}; /// # type u16 = zerocopy::byteorder::native_endian::U16; /// # type u32 = zerocopy::byteorder::native_endian::U32; /// #[derive(KnownLayout, FromBytes, IntoBytes, Immutable)] /// #[repr(C)] /// struct SliceDst<T, U> { /// t: T, /// u: [U], /// } /// /// type Src = SliceDst<u32, u16>; /// type Dst = SliceDst<u16, u8>; /// /// let mut bytes = [0, 1, 2, 3, 4, 5, 6, 7]; /// let src = Src::mut_from_bytes(&mut bytes[..]).unwrap(); /// let dst: &mut Dst = transmute_mut!(src); /// /// assert_eq!(dst.t.as_bytes(), [0, 1]); /// assert_eq!(dst.u, [2, 3, 4, 5, 6, 7]); /// /// assert_eq!(src.t.as_bytes(), [0, 1, 2, 3]); /// assert_eq!(src.u.len(), 2); /// assert_eq!(src.u.as_bytes(), [4, 5, 6, 7]); /// /// ``` #[macro_export]
macro_rules! transmute_mut {
($e:expr) => {{ // NOTE: This must be a macro (rather than a function with trait bounds) // because, for backwards-compatibility on v0.8.x, we use the autoref // specialization trick to dispatch to different `transmute_mut` // implementations: one which doesn't require `Src: KnownLayout + Dst: // KnownLayout` when `Src: Sized + Dst: Sized`, and one which requires // `KnownLayout` bounds otherwise.
// Ensure that the source type is a mutable reference. let e: &mut _ = $e;
#[allow(unused)] use $crate::util::macro_util::TransmuteMutDst as _; let t = $crate::util::macro_util::Wrap::new(e);
t.transmute_mut()
}}
}
/// Conditionally transmutes a value of one type to a value of another type of /// the same size. /// /// This macro behaves like an invocation of this function: /// /// ```ignore /// fn try_transmute<Src, Dst>(src: Src) -> Result<Dst, ValidityError<Src, Dst>> /// where /// Src: IntoBytes, /// Dst: TryFromBytes, /// size_of::<Src>() == size_of::<Dst>(), /// { /// # /* /// ... /// # */ /// } /// ``` /// /// However, unlike a function, this macro can only be invoked when the types of /// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are /// inferred from the calling context; they cannot be explicitly specified in /// the macro invocation. /// /// Note that the `Src` produced by the expression `$e` will *not* be dropped. /// Semantically, its bits will be copied into a new value of type `Dst`, the /// original `Src` will be forgotten, and the value of type `Dst` will be /// returned. /// /// # Examples /// /// ``` /// # use zerocopy::*; /// // 0u8 → bool = false /// assert_eq!(try_transmute!(0u8), Ok(false)); /// /// // 1u8 → bool = true /// assert_eq!(try_transmute!(1u8), Ok(true)); /// /// // 2u8 → bool = error /// assert!(matches!( /// try_transmute!(2u8), /// Result::<bool, _>::Err(ValidityError { .. }) /// )); /// ``` #[macro_export]
macro_rules! try_transmute {
($e:expr) => {{ // NOTE: This must be a macro (rather than a function with trait bounds) // because there's no way, in a generic context, to enforce that two // types have the same size. `core::mem::transmute` uses compiler magic // to enforce this so long as the types are concrete.
let e = $e; iffalse { // Check that the sizes of the source and destination types are // equal.
// SAFETY: This code is never executed.
Ok(unsafe { // Clippy: We can't annotate the types; this macro is designed // to infer the types from the calling context. #[allow(clippy::missing_transmute_annotations)]
$crate::util::macro_util::core_reexport::mem::transmute(e)
})
} else {
$crate::util::macro_util::try_transmute::<_, _>(e)
}
}}
}
/// Conditionally transmutes a mutable or immutable reference of one type to an /// immutable reference of another type of the same size and compatible /// alignment. /// /// This macro behaves like an invocation of this function: /// /// ```ignore /// fn try_transmute_ref<Src, Dst>(src: &Src) -> Result<&Dst, ValidityError<&Src, Dst>> /// where /// Src: IntoBytes + Immutable, /// Dst: TryFromBytes + Immutable, /// size_of::<Src>() == size_of::<Dst>(), /// align_of::<Src>() >= align_of::<Dst>(), /// { /// # /* /// ... /// # */ /// } /// ``` /// /// However, unlike a function, this macro can only be invoked when the types of /// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are /// inferred from the calling context; they cannot be explicitly specified in /// the macro invocation. /// /// # Examples /// /// ``` /// # use zerocopy::*; /// // 0u8 → bool = false /// assert_eq!(try_transmute_ref!(&0u8), Ok(&false)); /// /// // 1u8 → bool = true /// assert_eq!(try_transmute_ref!(&1u8), Ok(&true)); /// /// // 2u8 → bool = error /// assert!(matches!( /// try_transmute_ref!(&2u8), /// Result::<&bool, _>::Err(ValidityError { .. }) /// )); /// ``` /// /// # Alignment increase error message /// /// Because of limitations on macros, the error message generated when /// `try_transmute_ref!` is used to transmute from a type of lower alignment to /// a type of higher alignment is somewhat confusing. For example, the following /// code: /// /// ```compile_fail /// let increase_alignment: Result<&u16, _> = zerocopy::try_transmute_ref!(&[0u8; 2]); /// ``` /// /// ...generates the following error: /// /// ```text /// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types /// --> example.rs:1:47 /// | /// 1 | let increase_alignment: Result<&u16, _> = zerocopy::try_transmute_ref!(&[0u8; 2]); /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /// | /// = note: source type: `AlignOf<[u8; 2]>` (8 bits) /// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits) /// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `zerocopy::try_transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)/// ``` /// ``` /// /// This is saying that `max(align_of::<T>(), align_of::<U>()) != /// align_of::<T>()`, which is equivalent to `align_of::<T>() < /// align_of::<U>()`. #[macro_export]
macro_rules! try_transmute_ref {
($e:expr) => {{ // NOTE: This must be a macro (rather than a function with trait bounds) // because there's no way, in a generic context, to enforce that two // types have the same size. `core::mem::transmute` uses compiler magic // to enforce this so long as the types are concrete.
// Ensure that the source type is a reference or a mutable reference // (note that mutable references are implicitly reborrowed here). let e: &_ = $e;
#[allow(unreachable_code, unused, clippy::diverging_sub_expression)] iffalse { // This branch, though never taken, ensures that `size_of::<T>() == // size_of::<U>()` and that that `align_of::<T>() >= // align_of::<U>()`.
// `t` is inferred to have type `T` because it's assigned to `e` (of // type `&T`) as `&t`. letmut t = loop {};
e = &t;
// `u` is inferred to have type `U` because it's used as `Ok(&u)` as // the value returned from this branch. let u;
/// Conditionally transmutes a mutable reference of one type to a mutable /// reference of another type of the same size and compatible alignment. /// /// This macro behaves like an invocation of this function: /// /// ```ignore /// fn try_transmute_mut<Src, Dst>(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>> /// where /// Src: FromBytes + IntoBytes, /// Dst: TryFromBytes + IntoBytes, /// size_of::<Src>() == size_of::<Dst>(), /// align_of::<Src>() >= align_of::<Dst>(), /// { /// # /* /// ... /// # */ /// } /// ``` /// /// However, unlike a function, this macro can only be invoked when the types of /// `Src` and `Dst` are completely concrete. The types `Src` and `Dst` are /// inferred from the calling context; they cannot be explicitly specified in /// the macro invocation. /// /// # Examples /// /// ``` /// # use zerocopy::*; /// // 0u8 → bool = false /// let src = &mut 0u8; /// assert_eq!(try_transmute_mut!(src), Ok(&mut false)); /// /// // 1u8 → bool = true /// let src = &mut 1u8; /// assert_eq!(try_transmute_mut!(src), Ok(&mut true)); /// /// // 2u8 → bool = error /// let src = &mut 2u8; /// assert!(matches!( /// try_transmute_mut!(src), /// Result::<&mut bool, _>::Err(ValidityError { .. }) /// )); /// ``` /// /// # Alignment increase error message /// /// Because of limitations on macros, the error message generated when /// `try_transmute_ref!` is used to transmute from a type of lower alignment to /// a type of higher alignment is somewhat confusing. For example, the following /// code: /// /// ```compile_fail /// let src = &mut [0u8; 2]; /// let increase_alignment: Result<&mut u16, _> = zerocopy::try_transmute_mut!(src); /// ``` /// /// ...generates the following error: /// /// ```text /// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types /// --> example.rs:2:51 /// | /// 2 | let increase_alignment: Result<&mut u16, _> = zerocopy::try_transmute_mut!(src); /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ /// | /// = note: source type: `AlignOf<[u8; 2]>` (8 bits) /// = note: target type: `MaxAlignsOf<[u8; 2], u16>` (16 bits) /// = note: this error originates in the macro `$crate::assert_align_gt_eq` which comes from the expansion of the macro `zerocopy::try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info) /// ``` /// /// This is saying that `max(align_of::<T>(), align_of::<U>()) != /// align_of::<T>()`, which is equivalent to `align_of::<T>() < /// align_of::<U>()`. #[macro_export]
macro_rules! try_transmute_mut {
($e:expr) => {{ // NOTE: This must be a macro (rather than a function with trait bounds) // because there's no way, in a generic context, to enforce that two // types have the same size. `core::mem::transmute` uses compiler magic // to enforce this so long as the types are concrete.
// Ensure that the source type is a mutable reference. let e: &mut _ = $e;
#[allow(unreachable_code, unused, clippy::diverging_sub_expression)] iffalse { // This branch, though never taken, ensures that `size_of::<T>() == // size_of::<U>()` and that that `align_of::<T>() >= // align_of::<U>()`.
// `t` is inferred to have type `T` because it's assigned to `e` (of // type `&mut T`) as `&mut t`. letmut t = loop {};
e = &mut t;
// `u` is inferred to have type `U` because it's used as `Ok(&mut // u)` as the value returned from this branch. let u;
/// Includes a file and safely transmutes it to a value of an arbitrary type. /// /// The file will be included as a byte array, `[u8; N]`, which will be /// transmuted to another type, `T`. `T` is inferred from the calling context, /// and must implement [`FromBytes`]. /// /// The file is located relative to the current file (similarly to how modules /// are found). The provided path is interpreted in a platform-specific way at /// compile time. So, for instance, an invocation with a Windows path containing /// backslashes `\` would not compile correctly on Unix. /// /// `include_value!` is ignorant of byte order. For byte order-aware types, see /// the [`byteorder`] module. /// /// [`FromBytes`]: crate::FromBytes /// [`byteorder`]: crate::byteorder /// /// # Examples /// /// Assume there are two files in the same directory with the following /// contents: /// /// File `data` (no trailing newline): /// /// ```text /// abcd /// ``` /// /// File `main.rs`: /// /// ```rust /// use zerocopy::include_value; /// # macro_rules! include_value { /// # ($file:expr) => { zerocopy::include_value!(concat!("../testdata/include_value/", $file)) }; /// # } /// /// fn main() { /// let as_u32: u32 = include_value!("data"); /// assert_eq!(as_u32, u32::from_ne_bytes([b'a', b'b', b'c', b'd'])); /// let as_i32: i32 = include_value!("data"); /// assert_eq!(as_i32, i32::from_ne_bytes([b'a', b'b', b'c', b'd'])); /// } /// ``` /// /// # Use in `const` contexts /// /// This macro can be invoked in `const` contexts. #[doc(alias("include_bytes", "include_data", "include_type"))] #[macro_export]
macro_rules! include_value {
($file:expr $(,)?) => {
$crate::transmute!(*::core::include_bytes!($file))
};
}
// SAFETY: See inline. unsafeimpl $(<$($tyvar),*>)? $crate::TryFromBytes for $name$(<$($tyvar),*>)? where
$(
$($tuple_field_ty: $crate::FromBytes,)*
)?
$(
$($field_ty: $crate::FromBytes,)*
)?
{ fn is_bit_valid<A>(_c: $crate::Maybe<'_, Self, A>) -> bool where
A: $crate::pointer::invariant::Reference
{ // SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, and this `impl` block // requires all field types to be `FromBytes`. Thus, all // initialized byte sequences constitutes valid instances of // `Self`. true
}
// SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, and this `impl` block requires all // field types to be `FromBytes`, which is a sub-trait of `FromZeros`. unsafeimpl $(<$($tyvar),*>)? $crate::FromZeros for $name$(<$($tyvar),*>)? where
$(
$($tuple_field_ty: $crate::FromBytes,)*
)?
// SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, and this `impl` block requires all // field types to be `FromBytes`. unsafeimpl $(<$($tyvar),*>)? $crate::FromBytes for $name$(<$($tyvar),*>)? where
$(
$($tuple_field_ty: $crate::FromBytes,)*
)?
// SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, this `impl` block requires all field // types to be `IntoBytes`, and a padding check is used to ensures that // there are no padding bytes. unsafeimpl $(<$($tyvar),*>)? $crate::IntoBytes for $name$(<$($tyvar),*>)? where
$(
$($tuple_field_ty: $crate::IntoBytes,)*
)?
// SAFETY: This macro only accepts `#[repr(C)]` and // `#[repr(transparent)]` structs, and this `impl` block requires all // field types to be `Immutable`. unsafeimpl $(<$($tyvar),*>)? $crate::Immutable for $name$(<$($tyvar),*>)? where
$(
$($tuple_field_ty: $crate::Immutable,)*
)?
$(
$($field_ty: $crate::Immutable,)*
)?
{ fn only_derive_is_allowed_to_implement_this_trait() {}
}
};
(@assert_allowed_struct_repr #[repr(transparent)]) => {};
(@assert_allowed_struct_repr #[repr(C)]) => {};
(@assert_allowed_struct_repr #[$_attr:meta]) => {
compile_error!("repr must be `#[repr(transparent)]` or `#[repr(C)]`");
};
(
@struct_padding_check #[repr(transparent)]
$(($($tuple_field_ty:ty),*))?
$({$($field_ty:ty),*})?
) => { // SAFETY: `#[repr(transparent)]` structs cannot have the same layout as // their single non-zero-sized field, and so cannot have any padding // outside of that field. 0
};
(
@struct_padding_check #[repr(C)]
$(($($tuple_field_ty:ty),*))?
$({$($field_ty:ty),*})?
) => {
$crate::struct_padding!( Self,
[
$($($tuple_field_ty),*)?
$($($field_ty),*)?
]
)
};
( #[repr(C)]
$(#[$attr:meta])*
$vis:vis union $name:ident {
$(
$field_name:ident: $field_ty:ty,
)*
}
) => {
$(#[$attr])* #[repr(C)]
$vis union $name {
$(
$field_name: $field_ty,
)*
}
// SAFETY: See inline. unsafeimpl $crate::TryFromBytes for $name where
$(
$field_ty: $crate::FromBytes,
)*
{ fn is_bit_valid<A>(_c: $crate::Maybe<'_, Self, A>) -> bool where
A: $crate::pointer::invariant::Reference
{ // SAFETY: This macro only accepts `#[repr(C)]` unions, and this // `impl` block requires all field types to be `FromBytes`. // Thus, all initialized byte sequences constitutes valid // instances of `Self`. true
}
// SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl` // block requires all field types to be `FromBytes`, which is a // sub-trait of `FromZeros`. unsafeimpl $crate::FromZeros for $name where
$(
$field_ty: $crate::FromBytes,
)*
{ fn only_derive_is_allowed_to_implement_this_trait() {}
}
// SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl` // block requires all field types to be `FromBytes`. unsafeimpl $crate::FromBytes for $name where
$(
$field_ty: $crate::FromBytes,
)*
{ fn only_derive_is_allowed_to_implement_this_trait() {}
}
// SAFETY: This macro only accepts `#[repr(C)]` unions, this `impl` // block requires all field types to be `IntoBytes`, and a padding check // is used to ensures that there are no padding bytes before or after // any field. unsafeimpl $crate::IntoBytes for $name where
$(
$field_ty: $crate::IntoBytes,
)*
(): $crate::util::macro_util::PaddingFree< Self,
{
$crate::union_padding!( Self,
[$($field_ty),*]
)
},
>,
{ fn only_derive_is_allowed_to_implement_this_trait() {}
}
// SAFETY: This macro only accepts `#[repr(C)]` unions, and this `impl` // block requires all field types to be `Immutable`. unsafeimpl $crate::Immutable for $name where
$(
$field_ty: $crate::Immutable,
)*
{ fn only_derive_is_allowed_to_implement_this_trait() {}
}
};
}
#[cfg(test)] mod tests { usecrate::{
byteorder::native_endian::{U16, U32},
util::testutil::*,
*,
};
#[test] fn test_transmute() { // Test that memory is transmuted as expected. let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; let x: [[u8; 2]; 4] = transmute!(array_of_u8s);
assert_eq!(x, array_of_arrays); let x: [u8; 8] = transmute!(array_of_arrays);
assert_eq!(x, array_of_u8s);
// Test that memory is transmuted as expected when shrinking. let x: [[u8; 2]; 3] = transmute!(#![allow(shrink)] array_of_u8s);
assert_eq!(x, [[0u8, 1], [2, 3], [4, 5]]);
// Test that the source expression's value is forgotten rather than // dropped. #[derive(IntoBytes)] #[repr(transparent)] struct PanicOnDrop(()); impl Drop for PanicOnDrop { fn drop(&mutself) {
panic!("PanicOnDrop::drop");
}
} #[allow(clippy::let_unit_value)] let _: () = transmute!(PanicOnDrop(())); #[allow(clippy::let_unit_value)] let _: () = transmute!(#![allow(shrink)] PanicOnDrop(()));
// Test that `transmute!` works with `!Immutable` types. let x: usize = transmute!(UnsafeCell::new(1usize));
assert_eq!(x, 1); let x: UnsafeCell<usize> = transmute!(1usize);
assert_eq!(x.into_inner(), 1); let x: UnsafeCell<isize> = transmute!(UnsafeCell::new(1usize));
assert_eq!(x.into_inner(), 1);
}
// A `Sized` type which doesn't implement `KnownLayout` (it is "not // `KnownLayout`", or `Nkl`). // // This permits us to test that `transmute_ref!` and `transmute_mut!` work // for types which are `Sized + !KnownLayout`. When we added support for // slice DSTs in #1924, this new support relied on `KnownLayout`, but we // need to make sure to remain backwards-compatible with code which uses // these macros with types which are `!KnownLayout`. #[derive(FromBytes, IntoBytes, Immutable, PartialEq, Eq, Debug)] #[repr(transparent)] struct Nkl<T>(T);
#[test] fn test_transmute_ref() { // Test that memory is transmuted as expected. let array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; let array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; let x: &[[u8; 2]; 4] = transmute_ref!(&array_of_u8s);
assert_eq!(*x, array_of_arrays); let x: &[u8; 8] = transmute_ref!(&array_of_arrays);
assert_eq!(*x, array_of_u8s);
// Test that `transmute_ref!` is legal in a const context. const ARRAY_OF_U8S: [u8; 8] = [0u8, 1, 2, 3, 4, 5, 6, 7]; const ARRAY_OF_ARRAYS: [[u8; 2]; 4] = [[0, 1], [2, 3], [4, 5], [6, 7]]; #[allow(clippy::redundant_static_lifetimes)] const X: &'static [[u8; 2]; 4] = transmute_ref!(&ARRAY_OF_U8S);
assert_eq!(*X, ARRAY_OF_ARRAYS);
// Before 1.61.0, we can't define the `const fn transmute_ref` function // that we do on and after 1.61.0. #[cfg(not(zerocopy_generic_bounds_in_const_fn_1_61_0))]
{ // Test that `transmute_ref!` supports non-`KnownLayout` `Sized` types. const ARRAY_OF_NKL_U8S: Nkl<[u8; 8]> = Nkl([0u8, 1, 2, 3, 4, 5, 6, 7]); const ARRAY_OF_NKL_ARRAYS: Nkl<[[u8; 2]; 4]> = Nkl([[0, 1], [2, 3], [4, 5], [6, 7]]); const X_NKL: &Nkl<[[u8; 2]; 4]> = transmute_ref!(&ARRAY_OF_NKL_U8S);
assert_eq!(*X_NKL, ARRAY_OF_NKL_ARRAYS);
}
#[cfg(zerocopy_generic_bounds_in_const_fn_1_61_0)]
{ // Call through a generic function to make sure our autoref // specialization trick works even when types are generic. constfn transmute_ref<T, U>(t: &T) -> &U where
T: IntoBytes + Immutable,
U: FromBytes + Immutable,
{
transmute_ref!(t)
}
// Test that `transmute_ref!` works on slice DSTs in and that memory is // transmuted as expected. let slice_dst_of_u8s =
SliceDst::<U16, [u8; 2]>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap(); let slice_dst_of_u16s =
SliceDst::<U16, U16>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap(); let x: &SliceDst<U16, U16> = transmute_ref!(slice_dst_of_u8s);
assert_eq!(x, slice_dst_of_u16s);
let x: &[U16] = transmute_ref!(slice_dst_of_u16s); let slice_of_u16s: &[U16] = <[U16]>::ref_from_bytes(&[0, 1, 2, 3, 4, 5][..]).unwrap();
assert_eq!(x, slice_of_u16s);
// Test that transmuting from a type with larger trailing slice offset // and larger trailing slice element works. let bytes = &[0, 1, 2, 3, 4, 5, 6, 7][..]; let slice_dst_big = SliceDst::<U32, U16>::ref_from_bytes(bytes).unwrap(); let slice_dst_small = SliceDst::<U16, u8>::ref_from_bytes(bytes).unwrap(); let x: &SliceDst<U16, u8> = transmute_ref!(slice_dst_big);
assert_eq!(x, slice_dst_small);
// Test that it's legal to transmute a reference while shrinking the // lifetime (note that `X` has the lifetime `'static`). let x: &[u8; 8] = transmute_ref!(X);
assert_eq!(*x, ARRAY_OF_U8S);
// Test that `transmute_ref!` supports decreasing alignment. let u = AU64(0); let array = [0, 0, 0, 0, 0, 0, 0, 0]; let x: &[u8; 8] = transmute_ref!(&u);
assert_eq!(*x, array);
// Test that a mutable reference can be turned into an immutable one. letmut x = 0u8; #[allow(clippy::useless_transmute)] let y: &u8 = transmute_ref!(&mut x);
assert_eq!(*y, 0);
}
#[test] fn test_try_transmute() { // Test that memory is transmuted with `try_transmute` as expected. let array_of_bools = [false, true, false, true, false, true, false, true]; let array_of_arrays = [[0, 1], [0, 1], [0, 1], [0, 1]]; let x: Result<[[u8; 2]; 4], _> = try_transmute!(array_of_bools);
assert_eq!(x, Ok(array_of_arrays)); let x: Result<[bool; 8], _> = try_transmute!(array_of_arrays);
assert_eq!(x, Ok(array_of_bools));
// Test that `try_transmute!` works with `!Immutable` types. let x: Result<usize, _> = try_transmute!(UnsafeCell::new(1usize));
assert_eq!(x.unwrap(), 1); let x: Result<UnsafeCell<usize>, _> = try_transmute!(1usize);
assert_eq!(x.unwrap().into_inner(), 1); let x: Result<UnsafeCell<isize>, _> = try_transmute!(UnsafeCell::new(1usize));
assert_eq!(x.unwrap().into_inner(), 1);
impl<T> Drop for PanicOnDrop<T> { fn drop(&mutself) {
panic!("PanicOnDrop dropped");
}
}
// Since `try_transmute!` semantically moves its argument on failure, // the `PanicOnDrop` is not dropped, and thus this shouldn't panic. let x: Result<usize, _> = try_transmute!(PanicOnDrop(1usize));
assert_eq!(x, Ok(1));
// Since `try_transmute!` semantically returns ownership of its argument // on failure, the `PanicOnDrop` is returned rather than dropped, and // thus this shouldn't panic. let y: Result<bool, _> = try_transmute!(PanicOnDrop(2u8)); // We have to use `map_err` instead of comparing against // `Err(PanicOnDrop(2u8))` because the latter would create and then drop // its `PanicOnDrop` temporary, which would cause a panic.
assert_eq!(y.as_ref().map_err(|p| &p.src.0), Err::<&bool, _>(&tyle='color: green'>2u8));
mem::forget(y);
}
#[test] fn test_try_transmute_ref() { // Test that memory is transmuted with `try_transmute_ref` as expected. let array_of_bools = &[false, true, false, true, false, true, false, true]; let array_of_arrays = &[[0, 1], [0, 1], [0, 1], [0, 1]]; let x: Result<&[[u8; 2]; 4], _> = try_transmute_ref!(array_of_bools);
assert_eq!(x, Ok(array_of_arrays)); let x: Result<&[bool; 8], _> = try_transmute_ref!(array_of_arrays);
assert_eq!(x, Ok(array_of_bools));
// Test that it's legal to transmute a reference while shrinking the // lifetime.
{ let x: Result<&[[u8; 2]; 4], _> = try_transmute_ref!(array_of_bools);
assert_eq!(x, Ok(array_of_arrays));
}
// Test that `try_transmute_ref!` supports decreasing alignment. let u = AU64(0); let array = [0u8, 0, 0, 0, 0, 0, 0, 0]; let x: Result<&[u8; 8], _> = try_transmute_ref!(&u);
assert_eq!(x, Ok(&array));
// Test that a mutable reference can be turned into an immutable one. letmut x = 0u8; #[allow(clippy::useless_transmute)] let y: Result<&u8, _> = try_transmute_ref!(&mut x);
assert_eq!(y, Ok(&0));
}
#[test] fn test_try_transmute_mut() { // Test that memory is transmuted with `try_transmute_mut` as expected. let array_of_u8s = &mut [0u8, 1, 0, 1, 0, 1, 0, 1]; let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]]; let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_u8s);
assert_eq!(x, Ok(array_of_arrays));
// Test that it's legal to transmute a reference while shrinking the // lifetime. let array_of_bools = &mut [false, true, false, true, false, true, false, true]; let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
{ let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays);
assert_eq!(x, Ok(array_of_bools));
}
// Test that `try_transmute_mut!` supports decreasing alignment. let u = &mut AU64(0); let array = &mut [0u8, 0, 0, 0, 0, 0, 0, 0]; let x: Result<&mut [u8; 8], _> = try_transmute_mut!(u);
assert_eq!(x, Ok(array));
// Test that a mutable reference can be turned into an immutable one. letmut x = 0u8; #[allow(clippy::useless_transmute)] let y: Result<&mut u8, _> = try_transmute_mut!(&mut x);
assert_eq!(y, Ok(&mut0));
}
#[test] fn test_transmute_mut() { // Test that memory is transmuted as expected. letmut array_of_u8s = [0u8, 1, 2, 3, 4, 5, 6, 7]; letmut array_of_arrays = [[0, 1], [2, 3], [4, 5], [6, 7]]; let x: &mut [[u8; 2]; 4] = transmute_mut!(&mut array_of_u8s);
assert_eq!(*x, array_of_arrays); let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays);
assert_eq!(*x, array_of_u8s);
{ // Test that it's legal to transmute a reference while shrinking the // lifetime. let x: &mut [u8; 8] = transmute_mut!(&mut array_of_arrays);
assert_eq!(*x, array_of_u8s);
}
// Test that `transmute_mut!` supports decreasing alignment. letmut u = AU64(0); let array = [0, 0, 0, 0, 0, 0, 0, 0]; let x: &[u8; 8] = transmute_mut!(&mut u);
assert_eq!(*x, array);
// Test that a mutable reference can be turned into an immutable one. letmut x = 0u8; #[allow(clippy::useless_transmute)] let y: &u8 = transmute_mut!(&mut x);
assert_eq!(*y, 0);
// Test that `transmute_mut!` works on slice DSTs in and that memory is // transmuted as expected. letmut bytes = [0, 1, 2, 3, 4, 5, 6]; let slice_dst_of_u8s = SliceDst::<u8, [u8; 2]>::mut_from_bytes(&mut bytes[..]).unwrap(); letmut bytes = [0, 1, 2, 3, 4, 5, 6]; let slice_dst_of_u16s = SliceDst::<u8, U16>::mut_from_bytes(&mutbytes[..]).unwrap(); let x: &mut SliceDst<u8, U16> = transmute_mut!(slice_dst_of_u8s);
assert_eq!(x, slice_dst_of_u16s);
// Test that `transmute_mut!` works on slices that memory is transmuted // as expected. let array_of_u16s: &mut [u16] = &mut [0u16, 1, 2]; let array_of_i16s: &mut [i16] = &mut [0i16, 1, 2]; let x: &mut [i16] = transmute_mut!(array_of_u16s);
assert_eq!(x, array_of_i16s);
// Test that transmuting from a type with larger trailing slice offset // and larger trailing slice element works. letmut bytes = [0, 1, 2, 3, 4, 5, 6, 7]; let slice_dst_big = SliceDst::<U32, U16>::mut_from_bytes(&mut bytes[..]).unwrap(); letmut bytes = [0, 1, 2, 3, 4, 5, 6, 7]; let slice_dst_small = SliceDst::<U16, u8>::mut_from_bytes(&mut bytes[..]).unwrap(); let x: &mut SliceDst<U16, u8> = transmute_mut!(slice_dst_big);
assert_eq!(x, slice_dst_small);
}
cryptocorrosion_derive_traits! { #[repr(C)] /// Generic wrapper for unparameterized storage of any of the possible impls. /// Converting into and out of this type should be essentially free, although it may be more /// aligned than a particular impl requires. #[allow(non_camel_case_types)] #[derive(Copy, Clone)] pub union vec128_storage {
u32x4: [u32; 4],
u64x2: [u64; 2],
u128x1: [u128; 1],
sse2: __m128i,
}
}
// Make sure that our derive works for `#[repr(C)]` structs even though // cryptocorrosion doesn't currently have any.
cryptocorrosion_derive_traits! { #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq)] pubstruct ReprC(u8, u8, u16);
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.