1358 lines · 52.0 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.use super::*;use crate::pointer::{    BecauseInvariantsEq, BecauseMutationCompatible, MutationCompatible, TransmuteFromPtr,}; mod def {    use core::marker::PhantomData;     use crate::{        ByteSlice, ByteSliceMut, CloneableByteSlice, CopyableByteSlice, IntoByteSlice,        IntoByteSliceMut,    };     /// A typed reference derived from a byte slice.    ///    /// A `Ref<B, T>` is a reference to a `T` which is stored in a byte slice, `B`.    /// Unlike a native reference (`&T` or `&mut T`), `Ref<B, T>` has the same    /// mutability as the byte slice it was constructed from (`B`).    ///    /// # Examples    ///    /// `Ref` can be used to treat a sequence of bytes as a structured type, and    /// to read and write the fields of that type as if the byte slice reference    /// were simply a reference to that type.    ///    /// ```rust    /// use zerocopy::*;    /// # use zerocopy_derive::*;    ///    /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]    /// #[repr(C)]    /// struct UdpHeader {    ///     src_port: [u8; 2],    ///     dst_port: [u8; 2],    ///     length: [u8; 2],    ///     checksum: [u8; 2],    /// }    ///    /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]    /// #[repr(C, packed)]    /// struct UdpPacket {    ///     header: UdpHeader,    ///     body: [u8],    /// }    ///    /// impl UdpPacket {    ///     pub fn parse<B: ByteSlice>(bytes: B) -> Option<Ref<B, UdpPacket>> {    ///         Ref::from_bytes(bytes).ok()    ///     }    /// }    /// ```    pub struct Ref<B, T: ?Sized>(        // INVARIANTS: The referent (via `.deref`, `.deref_mut`, `.into`) byte        // slice is aligned to `T`'s alignment and its size corresponds to a        // valid size for `T`.        B,        PhantomData<T>,    );     impl<B, T: ?Sized> Ref<B, T> {        /// Constructs a new `Ref`.        ///        /// # Safety        ///        /// `bytes` dereferences (via [`deref`], [`deref_mut`], and [`into`]) to        /// a byte slice which is aligned to `T`'s alignment and whose size is a        /// valid size for `T`.        ///        /// [`deref`]: core::ops::Deref::deref        /// [`deref_mut`]: core::ops::DerefMut::deref_mut        /// [`into`]: core::convert::Into::into        pub(crate) unsafe fn new_unchecked(bytes: B) -> Ref<B, T> {            // INVARIANTS: The caller has promised that `bytes`'s referent is            // validly-aligned and has a valid size.            Ref(bytes, PhantomData)        }    }     impl<B: ByteSlice, T: ?Sized> Ref<B, T> {        /// Access the byte slice as a [`ByteSlice`].        ///        /// # Safety        ///        /// The caller promises not to call methods on the returned        /// [`ByteSlice`] other than `ByteSlice` methods (for example, via        /// `Any::downcast_ref`).        ///        /// `as_byte_slice` promises to return a `ByteSlice` whose referent is        /// validly-aligned for `T` and has a valid size for `T`.        pub(crate) unsafe fn as_byte_slice(&self) -> &impl ByteSlice {            // INVARIANTS: The caller promises not to call methods other than            // those on `ByteSlice`. Since `B: ByteSlice`, dereference stability            // guarantees that calling `ByteSlice` methods will not change the            // address or length of `self.0`'s referent.            //            // SAFETY: By invariant on `self.0`, the alignment and size            // post-conditions are upheld.            &self.0        }    }     impl<B: ByteSliceMut, T: ?Sized> Ref<B, T> {        /// Access the byte slice as a [`ByteSliceMut`].        ///        /// # Safety        ///        /// The caller promises not to call methods on the returned        /// [`ByteSliceMut`] other than `ByteSliceMut` methods (for example, via        /// `Any::downcast_mut`).        ///        /// `as_byte_slice` promises to return a `ByteSlice` whose referent is        /// validly-aligned for `T` and has a valid size for `T`.        pub(crate) unsafe fn as_byte_slice_mut(&mut self) -> &mut impl ByteSliceMut {            // INVARIANTS: The caller promises not to call methods other than            // those on `ByteSliceMut`. Since `B: ByteSlice`, dereference            // stability guarantees that calling `ByteSlice` methods will not            // change the address or length of `self.0`'s referent.            //            // SAFETY: By invariant on `self.0`, the alignment and size            // post-conditions are upheld.            &mut self.0        }    }     impl<'a, B: IntoByteSlice<'a>, T: ?Sized> Ref<B, T> {        /// Access the byte slice as an [`IntoByteSlice`].        ///        /// # Safety        ///        /// The caller promises not to call methods on the returned        /// [`IntoByteSlice`] other than `IntoByteSlice` methods (for example,        /// via `Any::downcast_ref`).        ///        /// `as_byte_slice` promises to return a `ByteSlice` whose referent is        /// validly-aligned for `T` and has a valid size for `T`.        pub(crate) unsafe fn into_byte_slice(self) -> impl IntoByteSlice<'a> {            // INVARIANTS: The caller promises not to call methods other than            // those on `IntoByteSlice`. Since `B: ByteSlice`, dereference            // stability guarantees that calling `ByteSlice` methods will not            // change the address or length of `self.0`'s referent.            //            // SAFETY: By invariant on `self.0`, the alignment and size            // post-conditions are upheld.            self.0        }    }     impl<'a, B: IntoByteSliceMut<'a>, T: ?Sized> Ref<B, T> {        /// Access the byte slice as an [`IntoByteSliceMut`].        ///        /// # Safety        ///        /// The caller promises not to call methods on the returned        /// [`IntoByteSliceMut`] other than `IntoByteSliceMut` methods (for        /// example, via `Any::downcast_mut`).        ///        /// `as_byte_slice` promises to return a `ByteSlice` whose referent is        /// validly-aligned for `T` and has a valid size for `T`.        pub(crate) unsafe fn into_byte_slice_mut(self) -> impl IntoByteSliceMut<'a> {            // INVARIANTS: The caller promises not to call methods other than            // those on `IntoByteSliceMut`. Since `B: ByteSlice`, dereference            // stability guarantees that calling `ByteSlice` methods will not            // change the address or length of `self.0`'s referent.            //            // SAFETY: By invariant on `self.0`, the alignment and size            // post-conditions are upheld.            self.0        }    }     impl<B: CloneableByteSlice + Clone, T: ?Sized> Clone for Ref<B, T> {        #[inline]        fn clone(&self) -> Ref<B, T> {            // INVARIANTS: Since `B: CloneableByteSlice`, `self.0.clone()` has            // the same address and length as `self.0`. Since `self.0` upholds            // the field invariants, so does `self.0.clone()`.            Ref(self.0.clone(), PhantomData)        }    }     // INVARIANTS: Since `B: CopyableByteSlice`, the copied `Ref`'s `.0` has the    // same address and length as the original `Ref`'s `.0`. Since the original    // upholds the field invariants, so does the copy.    impl<B: CopyableByteSlice + Copy, T: ?Sized> Copy for Ref<B, T> {}} #[allow(unreachable_pub)] // This is a false positive on our MSRV toolchain.pub use def::Ref; use crate::pointer::{    invariant::{Aligned, BecauseExclusive, Initialized, Unaligned, Valid},    BecauseRead, PtrInner,}; impl<B, T> Ref<B, T>where    B: ByteSlice,{    #[must_use = "has no side effects"]    pub(crate) fn sized_from(bytes: B) -> Result<Ref<B, T>, CastError<B, T>> {        if bytes.len() != mem::size_of::<T>() {            return Err(SizeError::new(bytes).into());        }        if let Err(err) = util::validate_aligned_to::<_, T>(bytes.deref()) {            return Err(err.with_src(bytes).into());        }         // SAFETY: We just validated size and alignment.        Ok(unsafe { Ref::new_unchecked(bytes) })    }} impl<B, T> Ref<B, T>where    B: SplitByteSlice,{    #[must_use = "has no side effects"]    pub(crate) fn sized_from_prefix(bytes: B) -> Result<(Ref<B, T>, B), CastError<B, T>> {        if bytes.len() < mem::size_of::<T>() {            return Err(SizeError::new(bytes).into());        }        if let Err(err) = util::validate_aligned_to::<_, T>(bytes.deref()) {            return Err(err.with_src(bytes).into());        }        let (bytes, suffix) = bytes.split_at(mem::size_of::<T>()).map_err(            #[inline(always)]            |b| SizeError::new(b).into(),        )?;        // SAFETY: We just validated alignment and that `bytes` is at least as        // large as `T`. `bytes.split_at(mem::size_of::<T>())?` ensures that the        // new `bytes` is exactly the size of `T`. By safety postcondition on        // `SplitByteSlice::split_at` we can rely on `split_at` to produce the        // correct `bytes` and `suffix`.        let r = unsafe { Ref::new_unchecked(bytes) };        Ok((r, suffix))    }     #[must_use = "has no side effects"]    pub(crate) fn sized_from_suffix(bytes: B) -> Result<(B, Ref<B, T>), CastError<B, T>> {        let bytes_len = bytes.len();        let split_at = if let Some(split_at) = bytes_len.checked_sub(mem::size_of::<T>()) {            split_at        } else {            return Err(SizeError::new(bytes).into());        };        let (prefix, bytes) = bytes.split_at(split_at).map_err(|b| SizeError::new(b).into())?;        if let Err(err) = util::validate_aligned_to::<_, T>(bytes.deref()) {            return Err(err.with_src(bytes).into());        }        // SAFETY: Since `split_at` is defined as `bytes_len - size_of::<T>()`,        // the `bytes` which results from `let (prefix, bytes) =        // bytes.split_at(split_at)?` has length `size_of::<T>()`. After        // constructing `bytes`, we validate that it has the proper alignment.        // By safety postcondition on `SplitByteSlice::split_at` we can rely on        // `split_at` to produce the correct `prefix` and `bytes`.        let r = unsafe { Ref::new_unchecked(bytes) };        Ok((prefix, r))    }} impl<B, T> Ref<B, T>where    B: ByteSlice,    T: KnownLayout + Immutable + ?Sized,{    /// Constructs a `Ref` from a byte slice.    ///    /// If the length of `source` is not a [valid size of `T`][valid-size], or    /// if `source` is not appropriately aligned for `T`, this returns `Err`. If    /// [`T: Unaligned`][t-unaligned], you can [infallibly discard the alignment    /// error][size-error-from].    ///    /// `T` may be a sized type, a slice, or a [slice DST][slice-dst].    ///    /// [valid-size]: crate::KnownLayout#what-is-a-valid-size    /// [t-unaligned]: crate::Unaligned    /// [size-error-from]: error/struct.SizeError.html#method.from-1    /// [slice-dst]: KnownLayout#dynamically-sized-types    ///    /// # Compile-Time Assertions    ///    /// This method cannot yet be used on unsized types whose dynamically-sized    /// component is zero-sized. Attempting to use this method on such types    /// results in a compile-time assertion error; e.g.:    ///    /// ```compile_fail,E0080    /// use zerocopy::*;    /// # use zerocopy_derive::*;    ///    /// #[derive(Immutable, KnownLayout)]    /// #[repr(C)]    /// struct ZSTy {    ///     leading_sized: u16,    ///     trailing_dst: [()],    /// }    ///    /// let _ = Ref::<_, ZSTy>::from_bytes(&b"UU"[..]); // ⚠ Compile Error!    /// ```    #[must_use = "has no side effects"]    #[inline]    pub fn from_bytes(source: B) -> Result<Ref<B, T>, CastError<B, T>> {        static_assert_dst_is_not_zst!(T);        if let Err(e) =            Ptr::from_ref(source.deref()).try_cast_into_no_leftover::<T, BecauseImmutable>(None)        {            return Err(e.with_src(()).with_src(source));        }        // SAFETY: `try_cast_into_no_leftover` validates size and alignment.        Ok(unsafe { Ref::new_unchecked(source) })    }} impl<B, T> Ref<B, T>where    B: SplitByteSlice,    T: KnownLayout + Immutable + ?Sized,{    /// Constructs a `Ref` from the prefix of a byte slice.    ///    /// This method computes the [largest possible size of `T`][valid-size] that    /// can fit in the leading bytes of `source`, then attempts to return both a    /// `Ref` to those bytes, and a reference to the remaining bytes. If there    /// are insufficient bytes, or if `source` is not appropriately aligned,    /// this returns `Err`. If [`T: Unaligned`][t-unaligned], you can    /// [infallibly discard the alignment error][size-error-from].    ///    /// `T` may be a sized type, a slice, or a [slice DST][slice-dst].    ///    /// [valid-size]: crate::KnownLayout#what-is-a-valid-size    /// [t-unaligned]: crate::Unaligned    /// [size-error-from]: error/struct.SizeError.html#method.from-1    /// [slice-dst]: KnownLayout#dynamically-sized-types    ///    /// # Compile-Time Assertions    ///    /// This method cannot yet be used on unsized types whose dynamically-sized    /// component is zero-sized. Attempting to use this method on such types    /// results in a compile-time assertion error; e.g.:    ///    /// ```compile_fail,E0080    /// use zerocopy::*;    /// # use zerocopy_derive::*;    ///    /// #[derive(Immutable, KnownLayout)]    /// #[repr(C)]    /// struct ZSTy {    ///     leading_sized: u16,    ///     trailing_dst: [()],    /// }    ///    /// let _ = Ref::<_, ZSTy>::from_prefix(&b"UU"[..]); // ⚠ Compile Error!    /// ```    #[must_use = "has no side effects"]    #[inline]    pub fn from_prefix(source: B) -> Result<(Ref<B, T>, B), CastError<B, T>> {        static_assert_dst_is_not_zst!(T);        let remainder = match Ptr::from_ref(source.deref())            .try_cast_into::<T, BecauseImmutable>(CastType::Prefix, None)        {            Ok((_, remainder)) => remainder,            Err(e) => {                return Err(e.with_src(()).with_src(source));            }        };         // SAFETY: `remainder` is constructed as a subset of `source`, and so it        // cannot have a larger size than `source`. Both of their `len` methods        // measure bytes (`source` deref's to `[u8]`, and `remainder` is a        // `Ptr<[u8]>`), so `source.len() >= remainder.len()`. Thus, this cannot        // underflow.        #[allow(unstable_name_collisions)]        let split_at = unsafe { source.len().unchecked_sub(remainder.len()) };        let (bytes, suffix) = source.split_at(split_at).map_err(|b| SizeError::new(b).into())?;        // SAFETY: `try_cast_into` validates size and alignment, and returns a        // `split_at` that indicates how many bytes of `source` correspond to a        // valid `T`. By safety postcondition on `SplitByteSlice::split_at` we        // can rely on `split_at` to produce the correct `source` and `suffix`.        let r = unsafe { Ref::new_unchecked(bytes) };        Ok((r, suffix))    }     /// Constructs a `Ref` from the suffix of a byte slice.    ///    /// This method computes the [largest possible size of `T`][valid-size] that    /// can fit in the trailing bytes of `source`, then attempts to return both    /// a `Ref` to those bytes, and a reference to the preceding bytes. If there    /// are insufficient bytes, or if that suffix of `source` is not    /// appropriately aligned, this returns `Err`. If [`T:    /// Unaligned`][t-unaligned], you can [infallibly discard the alignment    /// error][size-error-from].    ///    /// `T` may be a sized type, a slice, or a [slice DST][slice-dst].    ///    /// [valid-size]: crate::KnownLayout#what-is-a-valid-size    /// [t-unaligned]: crate::Unaligned    /// [size-error-from]: error/struct.SizeError.html#method.from-1    /// [slice-dst]: KnownLayout#dynamically-sized-types    ///    /// # Compile-Time Assertions    ///    /// This method cannot yet be used on unsized types whose dynamically-sized    /// component is zero-sized. Attempting to use this method on such types    /// results in a compile-time assertion error; e.g.:    ///    /// ```compile_fail,E0080    /// use zerocopy::*;    /// # use zerocopy_derive::*;    ///    /// #[derive(Immutable, KnownLayout)]    /// #[repr(C)]    /// struct ZSTy {    ///     leading_sized: u16,    ///     trailing_dst: [()],    /// }    ///    /// let _ = Ref::<_, ZSTy>::from_suffix(&b"UU"[..]); // ⚠ Compile Error!    /// ```    #[must_use = "has no side effects"]    #[inline]    pub fn from_suffix(source: B) -> Result<(B, Ref<B, T>), CastError<B, T>> {        static_assert_dst_is_not_zst!(T);        let remainder = match Ptr::from_ref(source.deref())            .try_cast_into::<T, BecauseImmutable>(CastType::Suffix, None)        {            Ok((_, remainder)) => remainder,            Err(e) => {                let e = e.with_src(());                return Err(e.with_src(source));            }        };         let split_at = remainder.len();        let (prefix, bytes) = source.split_at(split_at).map_err(|b| SizeError::new(b).into())?;        // SAFETY: `try_cast_into` validates size and alignment, and returns a        // `split_at` that indicates how many bytes of `source` correspond to a        // valid `T`. By safety postcondition on `SplitByteSlice::split_at` we        // can rely on `split_at` to produce the correct `prefix` and `bytes`.        let r = unsafe { Ref::new_unchecked(bytes) };        Ok((prefix, r))    }} impl<B, T> Ref<B, T>where    B: ByteSlice,    T: KnownLayout<PointerMetadata = usize> + Immutable + ?Sized,{    /// Constructs a `Ref` from the given bytes with DST length equal to `count`    /// without copying.    ///    /// This method attempts to return a `Ref` to the prefix of `source`    /// interpreted as a `T` with `count` trailing elements, and a reference to    /// the remaining bytes. If the length of `source` is not equal to the size    /// of `Self` with `count` elements, or if `source` is not appropriately    /// aligned, this returns `Err`. If [`T: Unaligned`][t-unaligned], you can    /// [infallibly discard the alignment error][size-error-from].    ///    /// [t-unaligned]: crate::Unaligned    /// [size-error-from]: error/struct.SizeError.html#method.from-1    ///    /// # Compile-Time Assertions    ///    /// This method cannot yet be used on unsized types whose dynamically-sized    /// component is zero-sized. Attempting to use this method on such types    /// results in a compile-time assertion error; e.g.:    ///    /// ```compile_fail,E0080    /// use zerocopy::*;    /// # use zerocopy_derive::*;    ///    /// #[derive(Immutable, KnownLayout)]    /// #[repr(C)]    /// struct ZSTy {    ///     leading_sized: u16,    ///     trailing_dst: [()],    /// }    ///    /// let _ = Ref::<_, ZSTy>::from_bytes_with_elems(&b"UU"[..], 42); // ⚠ Compile Error!    /// ```    #[inline]    pub fn from_bytes_with_elems(source: B, count: usize) -> Result<Ref<B, T>, CastError<B, T>> {        static_assert_dst_is_not_zst!(T);        let expected_len = match T::size_for_metadata(count) {            Some(len) => len,            None => return Err(SizeError::new(source).into()),        };        if source.len() != expected_len {            return Err(SizeError::new(source).into());        }        Self::from_bytes(source)

Lines 1–500 of 1358.