/// 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(
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. pubunsafetrait 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. #[inline] #[must_use] unsafefn split_at_unchecked(&self, l_len: usize) -> Split<&yle='color:red'>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]); /// ``` #[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. #[inline] #[must_use] unsafefn split_at_mut_unchecked(&mutself, l_len: usize) -> Split<&<span style='color:red'>mut Self> { // SAFETY: By precondition on the caller, `l_len <= self.len()`. unsafe { Split::<&mutSelf>::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]); /// ``` #[inline] fn split_at_mut(&mutself, l_len: usize) -> Option<Split<&='color:red'>mutSelf>> {
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. unsafeimpl<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)] pubstruct 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)] unsafefn 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]); /// ``` #[must_use = "has no side effects"] #[inline(always)] pubfn 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]); /// ``` #[must_use = "has no side effects"] #[inline(always)] pubfn 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]); /// ``` #[must_use = "has no side effects"] #[inline(always)] pubfn 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(), /// 2u16.to_be(), /// 3u16.to_be(), /// 4u16.to_be() /// ]; /// /// let packet = Packet::ref_from_bytes(bytes.as_bytes()).unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [0, 1, 0, 2, 0, 3, 0, 4]); /// /// // Attempt to split `packet` at `length`. /// let split = packet.split_at(packet.length.into()).unwrap(); /// /// // Use a dynamic check to prove that it's okay to return concurrent /// // references to `packet` and `rest`. /// let (packet, rest) = split.via_runtime_check().unwrap(); /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [0, 1, 0, 2]); /// assert_eq!(rest, [0, 3, 0, 4]); /// /// // Attempt to split `packet` at `length - 1`. /// let idx = packet.length.get() - 1; /// let split = packet.split_at(idx as usize).unwrap(); /// /// // Attempt (and fail) to use a dynamic check to prove that it's okay /// // to return concurrent references to `packet` and `rest`. Note that /// // this is a case of `via_runtime_check` being overly conservative. /// // Although the left and right parts indeed overlap, the `Immutable` /// // bound ensures that concurrently referencing these overlapping /// // parts is sound. /// assert!(split.via_runtime_check().is_err()); /// ``` #[must_use = "has no side effects"] #[inline(always)] pubfn via_runtime_check(self) -> Result<(&'a T, &'a [T::Elem]), Self> { matchself.into_ptr().via_runtime_check() {
Ok((l, r)) => Ok((l.as_ref(), r.as_ref())),
Err(s) => Err(s.into_ref()),
}
}
/// Unsafely produces the split parts of `self`. /// /// # Safety /// /// If `T` permits interior mutation, the trailing padding bytes of the left /// portion must not overlap the right portion. 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). Thus, for some types, this /// condition is dependent on the length of the left portion. #[must_use = "has no side effects"] #[inline(always)] pubunsafefn via_unchecked(self) -> (&'a T, &'a [T::Elem]) { // SAFETY: The aliasing of `self.into_ptr()` is not `Exclusive`, but the // caller has promised that if `T` permits interior mutation then the // left and right portions of `self` split at `l_len` do not overlap. let (l, r) = unsafe { self.into_ptr().via_unchecked() };
(l.as_ref(), r.as_ref())
}
}
impl<'a, T> Split<&'a mut T> where
T: ?Sized + SplitAt,
{ #[inline(always)] fn into_ptr(self) -> Split<Ptr<'a, T, (Exclusive, Aligned, Valid)>> { let source = Ptr::from_mut(self.source); // SAFETY: `Ptr::from_mut(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 [`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, 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]); /// ``` #[must_use = "has no side effects"] #[inline(always)] pubfn via_into_bytes(self) -> (&'a mut T, &'a mut [T::Elem]) where
T: IntoBytes,
{ let (l, r) = self.into_ptr().via_into_bytes();
(l.as_mut(), r.as_mut())
}
/// 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, IntoBytes, Unaligned)] /// #[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 `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]); /// /// rest.fill(0); /// } /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]); /// ``` #[must_use = "has no side effects"] #[inline(always)] pubfn via_unaligned(self) -> (&'a mut T, &'a mut [T::Elem]) where
T: Unaligned,
{ let (l, r) = self.into_ptr().via_unaligned();
(l.as_mut(), r.as_mut())
}
/// 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_into_bytes`] or [`Self::via_unaligned`], which /// have no runtime cost. /// /// # Examples /// /// ``` /// use zerocopy::{SplitAt, FromBytes}; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes, Debug)] /// #[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 a dynamic check to prove that it's okay to return concurrent /// // references to `packet` and `rest`. /// let (packet, rest) = split.via_runtime_check().unwrap(); /// /// 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]); /// ``` #[must_use = "has no side effects"] #[inline(always)] pubfn via_runtime_check(self) -> Result<(&'a mut T, &'a mut [T::Elem]), Self> { matchself.into_ptr().via_runtime_check() {
Ok((l, r)) => Ok((l.as_mut(), r.as_mut())),
Err(s) => Err(s.into_mut()),
}
}
/// Unsafely produces the split parts of `self`. /// /// # Safety /// /// The trailing padding bytes of the left portion must not overlap the /// right portion. 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). Thus, for some /// types, this condition is dependent on the length of the left portion. #[must_use = "has no side effects"] #[inline(always)] pubunsafefn via_unchecked(self) -> (&'a mut T, &'a mut [T::Elem]) { // SAFETY: The aliasing of `self.into_ptr()` is `Exclusive`, and the // caller has promised that the left and right portions of `self` split // at `l_len` do not overlap. let (l, r) = unsafe { self.into_ptr().via_unchecked() };
(l.as_mut(), r.as_mut())
}
}
impl<'a, T, I> Split<Ptr<'a, T, I>> where
T: ?Sized + SplitAt,
I: Invariants<Alignment = Aligned, Validity = Valid>,
{ fn into_ref(self) -> Split<&'a T> where
I: Invariants<Aliasing = Shared>,
{ // SAFETY: `self.source.as_ref()` points to exactly the same referent as // `self.source` and thus maintains the invariants of `self` with // respect to `l_len`. unsafe { Split::new(self.source.as_ref(), self.l_len) }
}
fn into_mut(self) -> Split<&'a mut T> where
I: Invariants<Aliasing = Exclusive>,
{ // SAFETY: `self.source.as_mut()` points to exactly the same referent as // `self.source` and thus maintains the invariants of `self` with // respect to `l_len`. unsafe { Split::new(self.source.unify_invariants().as_mut(), self.l_len) }
}
/// Produces the length of `self`'s left part. #[inline(always)] fn l_len(&self) -> MetadataOf<T> { // SAFETY: By invariant on `Split`, `self.l_len` is not greater than the // length of `self.source`. unsafe { MetadataOf::<T>::new_unchecked(self.l_len) }
}
/// Produces the split parts of `self`, using [`Immutable`] to ensure that /// it is sound to have concurrent references to both parts. #[inline(always)] fn via_immutable(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) where
T: Immutable,
I: Invariants<Aliasing = Shared>,
{ // SAFETY: `Aliasing = Shared` and `T: Immutable`. unsafe { self.via_unchecked() }
}
/// Produces the split parts of `self`, using [`IntoBytes`] to ensure that /// it is sound to have concurrent references to both parts. #[inline(always)] fn via_into_bytes(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) where
T: IntoBytes,
{ // SAFETY: By `T: IntoBytes`, `T` has no padding for any length. // Consequently, `T` can be split into non-overlapping parts at any // index. unsafe { self.via_unchecked() }
}
/// Produces the split parts of `self`, using [`Unaligned`] to ensure that /// it is sound to have concurrent references to both parts. #[inline(always)] fn via_unaligned(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) where
T: Unaligned,
{ // SAFETY: By `T: SplitAt + Unaligned`, `T` is either a slice or a // `repr(C)` or `repr(transparent)` slice DST that is well-aligned at // any address and length. If `T` is a slice DST with alignment 1, // `repr(C)` or `repr(transparent)` ensures that no padding is placed // after the final element of the trailing slice. Consequently, `T` can // be split into strictly non-overlapping parts any any index. unsafe { self.via_unchecked() }
}
/// 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. #[inline(always)] fn via_runtime_check(self) -> Result<(Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>), Self> { let l_len = self.l_len(); // FIXME(#1290): Once we require `KnownLayout` on all fields, add an // `IS_IMMUTABLE` associated const, and add `T::IS_IMMUTABLE ||` to the // below check. if l_len.padding_needed_for() == 0 { // SAFETY: By `T: SplitAt`, `T` is either `[T]`, or a `repr(C)` or // `repr(transparent)` slice DST, for which the trailing padding // needed to accommodate `l_len` trailing elements is // `l_len.padding_needed_for()`. If no trailing padding is required, // the left and right parts are strictly non-overlapping.
Ok(unsafe { self.via_unchecked() })
} else {
Err(self)
}
}
/// Unsafely produces the split parts of `self`. /// /// # Safety /// /// The caller promises that if `I::Aliasing` is [`Exclusive`] or `T` /// permits interior mutation, then `l_len.padding_needed_for() == 0`. #[inline(always)] unsafefn via_unchecked(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) { let l_len = self.l_len(); let inner = self.source.as_inner();
// SAFETY: By invariant on `Self::l_len`, `l_len` is not greater than // the length of `inner`'s trailing slice. let (left, right) = unsafe { inner.split_at_unchecked(l_len) };
// Lemma 0: `left` and `right` conform to the aliasing invariant // `I::Aliasing`. Proof: If `I::Aliasing` is `Exclusive` or `T` permits // interior mutation, the caller promises that `l_len.padding_needed_for() // == 0`. Consequently, by post-condition on `PtrInner::split_at_unchecked`, // there is no trailing padding after `left`'s final element that would // overlap into `right`. If `I::Aliasing` is shared and `T` forbids interior // mutation, then overlap between their referents is permissible.
// SAFETY: // 0. `left` conforms to the aliasing invariant of `I::Aliasing`, by Lemma 0. // 1. `left` conforms to the alignment invariant of `I::Alignment, because // the referents of `left` and `Self` have the same address and type // (and, thus, alignment requirement). // 2. `left` conforms to the validity invariant of `I::Validity`, neither // the type nor bytes of `left`'s referent have been changed. let left = unsafe { Ptr::from_inner(left) };
// SAFETY: // 0. `right` conforms to the aliasing invariant of `I::Aliasing`, by Lemma // 0. // 1. `right` conforms to the alignment invariant of `I::Alignment, because // if `ptr` with `I::Alignment = Aligned`, then by invariant on `T: // SplitAt`, the trailing slice of `ptr` (from which `right` is derived) // will also be well-aligned. // 2. `right` conforms to the validity invariant of `I::Validity`, // because `right: [T::Elem]` is derived from the trailing slice of // `ptr`, which, by contract on `T: SplitAt::Elem`, has type // `[T::Elem]`. The `left` part cannot be used to invalidate `right`, // because the caller promises that if `I::Aliasing` is `Exclusive` // or `T` permits interior mutation, then `l_len.padding_needed_for() // == 0` and thus the parts will be non-overlapping. let right = unsafe { Ptr::from_inner(right) };
#[allow(clippy::as_conversions)] fn test_split_at<const OFFSET: usize, const BUFFER_SIZE: usize>() { // Test `split_at` let n: usize = BUFFER_SIZE - OFFSET; let arr = [1; BUFFER_SIZE]; let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap(); for i in0..=n { let (l, r) = dst.split_at(i).unwrap().via_runtime_check().unwrap(); let l_sum: u8 = l.trailing.iter().sum(); let r_sum: u8 = r.iter().sum();
assert_eq!(l_sum, i as u8);
assert_eq!(r_sum, (n - i) as u8);
assert_eq!(l_sum + r_sum, n as u8);
}
// Test `split_at_mut` let n: usize = BUFFER_SIZE - OFFSET; letmut arr = [1; BUFFER_SIZE]; let dst = SliceDst::<OFFSET>::mut_from_bytes(&mut arr[..]).unwrap(); for i in0..=n { let (l, r) = dst.split_at_mut(i).unwrap().via_runtime_check().unwrap(); let l_sum: u8 = l.trailing.iter().sum(); let r_sum: u8 = r.iter().sum();
assert_eq!(l_sum, i as u8);
assert_eq!(r_sum, (n - i) as u8);
assert_eq!(l_sum + r_sum, n as u8);
}
}
let arr = [1u16; N]; let dst = SliceDst::ref_from_bytes(arr.as_bytes()).unwrap();
for i in0..N { let split = dst.split_at(i).unwrap().via_runtime_check(); if i % 2 == 1 {
assert!(split.is_ok());
} else {
assert!(split.is_err());
}
}
}
}
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.