1090 lines · 37.1 KB · Rust
RawDownload
// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT//// Copyright 2025 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::invariant::{Aligned, Exclusive, Invariants, Shared, Valid}; /// Types that can be split in two.////// This trait generalizes Rust's existing support for splitting slices to/// support slices and slice-based dynamically-sized types ("slice DSTs").////// # Implementation////// **Do not implement this trait yourself!** Instead, use/// [`#[derive(SplitAt)]`][derive]; e.g.:////// ```/// # use zerocopy_derive::{SplitAt, KnownLayout};/// #[derive(SplitAt, KnownLayout)]/// #[repr(C)]/// struct MyStruct<T: ?Sized> {/// # /*///     ...,/// # *////     // `SplitAt` types must have at least one field.///     field: T,/// }/// ```////// This derive performs a sophisticated, compile-time safety analysis to/// determine whether a type is `SplitAt`.////// # Safety////// This trait does not convey any safety guarantees to code outside this crate.////// You must not rely on the `#[doc(hidden)]` internals of `SplitAt`. Future/// releases of zerocopy may make backwards-breaking changes to these items,/// including changes that only affect soundness, which may cause code which/// uses those items to silently become unsound.///#[cfg_attr(feature = "derive", doc = "[derive]: zerocopy_derive::SplitAt")]#[cfg_attr(    not(feature = "derive"),    doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.SplitAt.html"),)]#[cfg_attr(    not(no_zerocopy_diagnostic_on_unimplemented_1_78_0),    diagnostic::on_unimplemented(note = "Consider adding `#[derive(SplitAt)]` to `{Self}`"))]// # Safety//// The trailing slice is well-aligned for its element type. `Self` is `[T]`, or// a `repr(C)` or `repr(transparent)` slice DST.pub unsafe trait SplitAt: KnownLayout<PointerMetadata = usize> {    /// The element type of the trailing slice.    type Elem;     #[doc(hidden)]    fn only_derive_is_allowed_to_implement_this_trait()    where        Self: Sized;     /// Unsafely splits `self` in two.    ///    /// # Safety    ///    /// The caller promises that `l_len` is not greater than the length of    /// `self`'s trailing slice.    ///    #[doc = codegen_section!(        header = "h5",        bench = "split_at_unchecked",        format = "coco",        arity = 2,        [            open            @index 1            @title "Unsized"            @variant "dynamic_size"        ],        [            @index 2            @title "Dynamically Padded"            @variant "dynamic_padding"        ]    )]    #[inline]    #[must_use]    unsafe fn split_at_unchecked(&self, l_len: usize) -> Split<&Self> {        // SAFETY: By precondition on the caller, `l_len <= self.len()`.        unsafe { Split::<&Self>::new(self, l_len) }    }     /// Attempts to split `self` in two.    ///    /// Returns `None` if `l_len` is greater than the length of `self`'s    /// trailing slice.    ///    /// # Examples    ///    /// ```    /// use zerocopy::{SplitAt, FromBytes};    /// # use zerocopy_derive::*;    ///    /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable)]    /// #[repr(C)]    /// struct Packet {    ///     length: u8,    ///     body: [u8],    /// }    ///    /// // These bytes encode a `Packet`.    /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];    ///    /// let packet = Packet::ref_from_bytes(bytes).unwrap();    ///    /// assert_eq!(packet.length, 4);    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);    ///    /// // Attempt to split `packet` at `length`.    /// let split = packet.split_at(packet.length as usize).unwrap();    ///    /// // Use the `Immutable` bound on `Packet` to prove that it's okay to    /// // return concurrent references to `packet` and `rest`.    /// let (packet, rest) = split.via_immutable();    ///    /// assert_eq!(packet.length, 4);    /// assert_eq!(packet.body, [1, 2, 3, 4]);    /// assert_eq!(rest, [5, 6, 7, 8, 9]);    /// ```    ///    #[doc = codegen_section!(        header = "h5",        bench = "split_at",        format = "coco",        arity = 2,        [            open            @index 1            @title "Unsized"            @variant "dynamic_size"        ],        [            @index 2            @title "Dynamically Padded"            @variant "dynamic_padding"        ]    )]    #[inline]    #[must_use = "has no side effects"]    fn split_at(&self, l_len: usize) -> Option<Split<&Self>> {        MetadataOf::new_in_bounds(self, l_len).map(            #[inline(always)]            |l_len| {                // SAFETY: We have ensured that `l_len <= self.len()` (by                // post-condition on `MetadataOf::new_in_bounds`)                unsafe { Split::new(self, l_len.get()) }            },        )    }     /// Unsafely splits `self` in two.    ///    /// # Safety    ///    /// The caller promises that `l_len` is not greater than the length of    /// `self`'s trailing slice.    ///    #[doc = codegen_header!("h5", "split_at_mut_unchecked")]    ///    /// See [`SplitAt::split_at_unchecked`](#method.split_at_unchecked.codegen).    #[inline]    #[must_use]    unsafe fn split_at_mut_unchecked(&mut self, l_len: usize) -> Split<&mut Self> {        // SAFETY: By precondition on the caller, `l_len <= self.len()`.        unsafe { Split::<&mut Self>::new(self, l_len) }    }     /// Attempts to split `self` in two.    ///    /// Returns `None` if `l_len` is greater than the length of `self`'s    /// trailing slice, or if the given `l_len` would result in [the trailing    /// padding](KnownLayout#slice-dst-layout) of the left portion overlapping    /// the right portion.    ///    ///    /// # Examples    ///    /// ```    /// use zerocopy::{SplitAt, FromBytes};    /// # use zerocopy_derive::*;    ///    /// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes)]    /// #[repr(C)]    /// struct Packet<B: ?Sized> {    ///     length: u8,    ///     body: B,    /// }    ///    /// // These bytes encode a `Packet`.    /// let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];    ///    /// let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap();    ///    /// assert_eq!(packet.length, 4);    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);    ///    /// {    ///     // Attempt to split `packet` at `length`.    ///     let split = packet.split_at_mut(packet.length as usize).unwrap();    ///    ///     // Use the `IntoBytes` bound on `Packet` to prove that it's okay to    ///     // return concurrent references to `packet` and `rest`.    ///     let (packet, rest) = split.via_into_bytes();    ///    ///     assert_eq!(packet.length, 4);    ///     assert_eq!(packet.body, [1, 2, 3, 4]);    ///     assert_eq!(rest, [5, 6, 7, 8, 9]);    ///    ///     rest.fill(0);    /// }    ///    /// assert_eq!(packet.length, 4);    /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]);    /// ```    ///    #[doc = codegen_header!("h5", "split_at_mut")]    ///    /// See [`SplitAt::split_at`](#method.split_at.codegen).    #[inline]    fn split_at_mut(&mut self, l_len: usize) -> Option<Split<&mut Self>> {        MetadataOf::new_in_bounds(self, l_len).map(            #[inline(always)]            |l_len| {                // SAFETY: We have ensured that `l_len <= self.len()` (by                // post-condition on `MetadataOf::new_in_bounds`)                unsafe { Split::new(self, l_len.get()) }            },        )    }} // SAFETY: `[T]`'s trailing slice is `[T]`, which is trivially aligned.unsafe impl<T> SplitAt for [T] {    type Elem = T;     #[inline]    #[allow(dead_code)]    fn only_derive_is_allowed_to_implement_this_trait()    where        Self: Sized,    {    }} /// A `T` that has been split into two possibly-overlapping parts.////// For some dynamically sized types, the padding that appears after the/// trailing slice field [is a dynamic function of the trailing slice/// length](KnownLayout#slice-dst-layout). If `T` is split at a length that/// requires trailing padding, the trailing padding of the left part of the/// split `T` will overlap the right part. If `T` is a mutable reference or/// permits interior mutation, you must ensure that the left and right parts do/// not overlap. You can do this at zero-cost using using/// [`Self::via_immutable`], [`Self::via_into_bytes`], or/// [`Self::via_unaligned`], or with a dynamic check by using/// [`Self::via_runtime_check`].#[derive(Debug)]pub struct Split<T> {    /// A pointer to the source slice DST.    source: T,    /// The length of the future left half of `source`.    ///    /// # Safety    ///    /// If `source` is a pointer to a slice DST, `l_len` is no greater than    /// `source`'s length.    l_len: usize,} impl<T> Split<T> {    /// Produces a `Split` of `source` with `l_len`.    ///    /// # Safety    ///    /// `l_len` is no greater than `source`'s length.    #[inline(always)]    unsafe fn new(source: T, l_len: usize) -> Self {        Self { source, l_len }    }} impl<'a, T> Split<&'a T>where    T: ?Sized + SplitAt,{    #[inline(always)]    fn into_ptr(self) -> Split<Ptr<'a, T, (Shared, Aligned, Valid)>> {        let source = Ptr::from_ref(self.source);        // SAFETY: `Ptr::from_ref(self.source)` points to exactly `self.source`        // and thus maintains the invariants of `self` with respect to `l_len`.        unsafe { Split::new(source, self.l_len) }    }     /// Produces the split parts of `self`, using [`Immutable`] to ensure that    /// it is sound to have concurrent references to both parts.    ///    /// # Examples    ///    /// ```    /// use zerocopy::{SplitAt, FromBytes};    /// # use zerocopy_derive::*;    ///    /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable)]    /// #[repr(C)]    /// struct Packet {    ///     length: u8,    ///     body: [u8],    /// }    ///    /// // These bytes encode a `Packet`.    /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];    ///    /// let packet = Packet::ref_from_bytes(bytes).unwrap();    ///    /// assert_eq!(packet.length, 4);    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);    ///    /// // Attempt to split `packet` at `length`.    /// let split = packet.split_at(packet.length as usize).unwrap();    ///    /// // Use the `Immutable` bound on `Packet` to prove that it's okay to    /// // return concurrent references to `packet` and `rest`.    /// let (packet, rest) = split.via_immutable();    ///    /// assert_eq!(packet.length, 4);    /// assert_eq!(packet.body, [1, 2, 3, 4]);    /// assert_eq!(rest, [5, 6, 7, 8, 9]);    /// ```    ///    #[doc = codegen_section!(        header = "h5",        bench = "split_via_immutable",        format = "coco",        arity = 2,        [            open            @index 1            @title "Unsized"            @variant "dynamic_size"        ],        [            @index 2            @title "Dynamically Padded"            @variant "dynamic_padding"        ]    )]    #[must_use = "has no side effects"]    #[inline(always)]    pub fn via_immutable(self) -> (&'a T, &'a [T::Elem])    where        T: Immutable,    {        let (l, r) = self.into_ptr().via_immutable();        (l.as_ref(), r.as_ref())    }     /// Produces the split parts of `self`, using [`IntoBytes`] to ensure that    /// it is sound to have concurrent references to both parts.    ///    /// # Examples    ///    /// ```    /// use zerocopy::{SplitAt, FromBytes};    /// # use zerocopy_derive::*;    ///    /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable, IntoBytes)]    /// #[repr(C)]    /// struct Packet<B: ?Sized> {    ///     length: u8,    ///     body: B,    /// }    ///    /// // These bytes encode a `Packet`.    /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];    ///    /// let packet = Packet::<[u8]>::ref_from_bytes(bytes).unwrap();    ///    /// assert_eq!(packet.length, 4);    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);    ///    /// // Attempt to split `packet` at `length`.    /// let split = packet.split_at(packet.length as usize).unwrap();    ///    /// // Use the `IntoBytes` bound on `Packet` to prove that it's okay to    /// // return concurrent references to `packet` and `rest`.    /// let (packet, rest) = split.via_into_bytes();    ///    /// assert_eq!(packet.length, 4);    /// assert_eq!(packet.body, [1, 2, 3, 4]);    /// assert_eq!(rest, [5, 6, 7, 8, 9]);    /// ```    ///    #[doc = codegen_header!("h5", "split_via_into_bytes")]    ///    /// See [`Split::via_immutable`](#method.split_via_immutable.codegen).    #[must_use = "has no side effects"]    #[inline(always)]    pub fn via_into_bytes(self) -> (&'a T, &'a [T::Elem])    where        T: IntoBytes,    {        let (l, r) = self.into_ptr().via_into_bytes();        (l.as_ref(), r.as_ref())    }     /// Produces the split parts of `self`, using [`Unaligned`] to ensure that    /// it is sound to have concurrent references to both parts.    ///    /// # Examples    ///    /// ```    /// use zerocopy::{SplitAt, FromBytes};    /// # use zerocopy_derive::*;    ///    /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable, Unaligned)]    /// #[repr(C)]    /// struct Packet {    ///     length: u8,    ///     body: [u8],    /// }    ///    /// // These bytes encode a `Packet`.    /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];    ///    /// let packet = Packet::ref_from_bytes(bytes).unwrap();    ///    /// assert_eq!(packet.length, 4);    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);    ///    /// // Attempt to split `packet` at `length`.    /// let split = packet.split_at(packet.length as usize).unwrap();    ///    /// // Use the `Unaligned` bound on `Packet` to prove that it's okay to    /// // return concurrent references to `packet` and `rest`.    /// let (packet, rest) = split.via_unaligned();    ///    /// assert_eq!(packet.length, 4);    /// assert_eq!(packet.body, [1, 2, 3, 4]);    /// assert_eq!(rest, [5, 6, 7, 8, 9]);    /// ```    ///    #[doc = codegen_header!("h5", "split_via_unaligned")]    ///    /// See [`Split::via_immutable`](#method.split_via_immutable.codegen).    #[must_use = "has no side effects"]    #[inline(always)]    pub fn via_unaligned(self) -> (&'a T, &'a [T::Elem])    where        T: Unaligned,    {        let (l, r) = self.into_ptr().via_unaligned();        (l.as_ref(), r.as_ref())    }     /// Produces the split parts of `self`, using a dynamic check to ensure that    /// it is sound to have concurrent references to both parts. You should    /// prefer using [`Self::via_immutable`], [`Self::via_into_bytes`], or    /// [`Self::via_unaligned`], which have no runtime cost.    ///    /// Note that this check is overly conservative if `T` is [`Immutable`]; for    /// some types, this check will reject some splits which    /// [`Self::via_immutable`] will accept.    ///    /// # Examples    ///    /// ```    /// use zerocopy::{SplitAt, FromBytes, IntoBytes, network_endian::U16};    /// # use zerocopy_derive::*;    ///    /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable, Debug)]    /// #[repr(C, align(2))]    /// struct Packet {    ///     length: U16,    ///     body: [u8],    /// }    ///    /// // These bytes encode a `Packet`.    /// let bytes = [    ///     4u16.to_be(),    ///     1u16.to_be(),

Lines 1–500 of 1090.