1825 lines · 64.6 KB · Rust
RawDownload
// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT//// Copyright 2024 The Fuchsia Authors//// Licensed under the 2-Clause BSD License <LICENSE-BSD or// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.// This file may not be copied, modified, or distributed except according to// those terms. /// 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.///#[doc = codegen_section!(    header = "h2",    bench = "transmute",    format = "coco_static_size",)]#[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) => {{        let mut e = $e;        if false {            // 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 `repr(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)            };             if false {                // 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;        if false {            // 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, between unsized/// (i.e., `?Sized`) types, and from a `Sized` type to an unsized type. 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`.///#[doc = codegen_section!(    header = "h2",    bench = "transmute_ref",    format = "coco",    arity = 2,    [        open        @index 1        @title "Sized"        @variant "static_size"    ],    [        @index 2        @title "Unsized"        @variant "dynamic_size"    ])]#[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)]        if false {            // 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`.             struct AssertSrcIsIntoBytes<'a, T: ?::core::marker::Sized + $crate::IntoBytes>(&'a T);            struct AssertSrcIsImmutable<'a, T: ?::core::marker::Sized + $crate::Immutable>(&'a T);            struct AssertDstIsFromBytes<'a, U: ?::core::marker::Sized + $crate::FromBytes>(&'a U);            struct AssertDstIsImmutable<'a, T: ?::core::marker::Sized + $crate::Immutable>(&'a T);             let _ = AssertSrcIsIntoBytes(e);            let _ = AssertSrcIsImmutable(e);             if true {                #[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);             if false {                // This branch exists solely to force the compiler to infer the                // type of `Dst` *before* it attempts to resolve the method call                // to `transmute_ref` in the `else` branch.                //                // Without this, if `Src` is `Sized` but `Dst` is `!Sized`, the                // compiler will eagerly select the inherent impl of                // `transmute_ref` (which requires `Dst: Sized`) because inherent                // methods take priority over trait methods. It does this before                // it realizes `Dst` is `!Sized`, leading to a compile error when                // it checks the bounds later.                //                // By calling this helper (which returns `&Dst`), we force `Dst`                // to be fully resolved. By the time it gets to the `else`                // branch, the compiler knows `Dst` is `!Sized`, properly                // disqualifies the inherent method, and falls back to the trait                // implementation.                t.transmute_ref_inference_helper()            } else {                // SAFETY: The outer `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 + ?Sized,///     Dst: FromBytes + IntoBytes + ?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_mut!` supports transmuting between `Sized` types, between unsized/// (i.e., `?Sized`) types, and from a `Sized` type to an unsized type. 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];

Lines 1–500 of 1825.