Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475// 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, Safe, Shared};
/// 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").////// For a `repr(C, packed)` or `repr(C, packed(N))` struct, the derive wraps/// the trailing field's [`Elem`](Self::Elem) in [`Unalign`]. The returned/// slice can therefore be accessed even when packing misaligns the original/// elements. Each packed struct in the trailing-field chain adds one wrapper;/// unpacked structs and [`ManuallyDrop`] forward their trailing type's `Elem`.////// # 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`.////// A packed struct exposes its trailing elements through `Unalign`:////// ```/// use zerocopy::{FromBytes, SplitAt, Unalign};/// # use zerocopy_derive::*;////// #[derive(FromBytes, IntoBytes, KnownLayout, SplitAt)]/// #[repr(C, packed)]/// struct Packet {/// tag: u8,/// words: [u16],/// }////// let mut bytes = [0u8; 5];/// let packet = Packet::mut_from_bytes(&mut bytes[..]).unwrap();/// let (left, right): (&mut Packet, &mut [Unalign<u16>]) =/// packet.split_at_mut(1).unwrap().via_into_bytes();/// left.tag = 1;/// right[0] = Unalign::new(0x0202);/// assert_eq!(bytes, [1, 0, 0, 2, 2]);/// ```////// # 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//// `Self` is a slice, a `repr(C)` (possibly packed) or `repr(transparent)` slice// DST, or `ManuallyDrop<T>` for some `T: SplitAt`.//// `Self::Elem` has the same size, bit validity, and `UnsafeCell` coverage as// the actual trailing element type. Access through either representation// preserves the other's validity, including writes through mutable references// and interior mutation through shared references. For every aligned `Self`,// its trailing slice's address is aligned for `Self::Elem`.pub unsafe trait SplitAt: KnownLayout<PointerMetadata = usize> { /// The element type exposed by the split's returned slice. /// /// For `[T]`, this is `T`. For a struct, this is the trailing field's `Elem`, /// wrapped in [`Unalign`] if the struct is packed. Nested packed structs /// produce nested `Unalign` wrappers. 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. /// /// # 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]` exposes its own element type, preserving size, validity, and// `UnsafeCell` coverage. An aligned slice is aligned for its elements.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, { }}
// SAFETY: `ManuallyDrop<T>` has the same layout and bit validity as `T` [1].// Its `KnownLayout` implementation preserves `T`'s metadata and trailing-slice// layout. Forwarding `T::Elem` therefore preserves its size, validity, and// alignment guarantees. Its `UnsafeCell` coverage also matches `T`'s, as// established for `ManuallyDrop` in `impls.rs`; accesses through the forwarded// element representation preserve validity in both directions.//// [1] Per https://doc.rust-lang.org/1.93.0/std/mem/struct.ManuallyDrop.html://// `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as// `T`unsafe impl<T: ?Sized + SplitAt> SplitAt for ManuallyDrop<T> { type Elem = T::Elem;
#[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. Use [`Self::via_into_bytes`] or/// [`Self::via_no_dynamic_padding`] to establish this without a runtime check,/// or [`Self::via_runtime_check`] to check a particular split. Shared references/// to an [`Immutable`] type may overlap; use [`Self::via_immutable`] in that/// case.#[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, Safe)>> { 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 [`Self::via_no_dynamic_padding`]. #[deprecated(note = "use `Split::via_no_dynamic_padding` instead")] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] pub fn via_unaligned(self) -> (&'a T, &'a [T::Elem]) where T: Unaligned, { self.via_no_dynamic_padding() }
/// Produces the split parts of `self` using a compile-time assertion to /// ensure that it is unconditionally sound to have concurrent references to /// both parts. /// /// When possible, you should prefer using [`Self::via_into_bytes`], which /// ensures this safety property through regular trait bounds. /// /// # Examples /// /// In the below example, a single byte of padding exists (on most /// platforms) between `Packet<[u16]>`'s `length` and `body` fields, /// precluding the use of [`Self::via_into_bytes`]. /// /// ``` /// use zerocopy::SplitAt; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, KnownLayout)] /// #[repr(C)] /// struct Packet<B: ?Sized> { /// length: u8, /// body: B, /// } /// /// let packet: &Packet<[u16]> = &Packet { length: 4, body: [1u16, 2, 3, 4, 5, 6, 7, 8, 9] }; /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); /// /// if let Some(split) = packet.split_at(packet.length as usize) { /// // Every body length requires no trailing padding. /// let (packet, rest) = split.via_no_dynamic_padding(); /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4]); /// assert_eq!(rest, [5, 6, 7, 8, 9]); /// } else { /// unreachable!("The packet's length field is within its body"); /// } /// ``` /// /// # Compile-Time Assertions /// /// This method rejects at compile-time any type that admits dynamic /// trailing padding. In the below example, some `split_at` indices would /// produce left parts whose trailing padding overlaps with the right part: /// /// ```compile_fail,E0080 /// use zerocopy::SplitAt; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, KnownLayout)] /// #[repr(C, align(2))] /// struct Packet<B: ?Sized> { /// length: u16, /// body: B, /// } /// /// let packet: &Packet<[u8]> = &Packet { length: 4, body: [1u8, 2, 3, 4, 5, 6, 7, 8, 9] }; /// /// if let Some(split) = packet.split_at(packet.length as usize) { /// let _ = split.via_no_dynamic_padding(); // ⚠ Compile Error! /// } else { /// unreachable!("The packet's length field is within its body"); /// } /// ``` /// /// If you need to split such types, use [`Self::via_runtime_check`]. /// #[doc = codegen_header!("h5", "split_via_no_dynamic_padding")] /// /// See [`Split::via_immutable`](#method.split_via_immutable.codegen). #[must_use = "has no side effects"] #[inline(always)] pub fn via_no_dynamic_padding(self) -> (&'a T, &'a [T::Elem]) { let (l, r) = self.into_ptr().via_no_dynamic_padding(); (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_no_dynamic_padding`], which perform no runtime check. /// /// 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; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, KnownLayout)] /// #[repr(C, align(2))] /// struct Packet<B: ?Sized> { /// length: u16, /// body: B, /// } /// /// let packet: &Packet<[u8]> = &Packet { length: 4, body: [1u8, 2, 3, 4, 5, 6, 7, 8, 9] }; /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); /// /// // The two-byte prefix and four-byte body need no trailing padding. /// if let Some(split) = packet.split_at(packet.length as usize) { /// if let Ok((packet, rest)) = split.via_runtime_check() { /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4]); /// assert_eq!(rest, [5, 6, 7, 8, 9]); /// } else { /// unreachable!("A four-byte body requires no trailing padding"); /// } /// } else { /// unreachable!("The packet's length field is within its body"); /// } /// /// // A three-byte body needs a padding byte that would overlap `rest`. /// if let Some(split) = packet.split_at((packet.length - 1) as usize) { /// assert!(split.via_runtime_check().is_err()); /// } else { /// unreachable!("One less than the packet's length is within its body"); /// } /// ``` /// #[doc = codegen_section!( header = "h5", bench = "split_via_runtime_check", 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_runtime_check(self) -> Result<(&'a T, &'a [T::Elem]), Self> { match self.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. /// #[doc = codegen_section!( header = "h5", bench = "split_via_unchecked", 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 unsafe fn 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, Safe)>> { 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]); /// ``` /// /// # Code Generation /// /// See [`Split::via_immutable`](#method.split_via_immutable.codegen). #[must_use = "has no side effects"] #[inline(always)] pub fn 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 [`Self::via_no_dynamic_padding`]. #[deprecated(note = "use `Split::via_no_dynamic_padding` instead")] #[doc(hidden)] #[must_use = "has no side effects"] #[inline(always)] pub fn via_unaligned(self) -> (&'a mut T, &'a mut [T::Elem]) where T: Unaligned, { self.via_no_dynamic_padding() }
/// Produces the split parts of `self` using a compile-time assertion to /// ensure that it is unconditionally sound to have concurrent references to /// both parts. /// /// When possible, you should prefer using [`Self::via_into_bytes`], which /// ensures this safety property through regular trait bounds. /// /// # Examples /// /// In the below example, a single byte of padding exists (on most /// platforms) between `Packet<[u16]>`'s `length` and `body` fields, /// precluding the use of [`Self::via_into_bytes`]. /// /// ``` /// use zerocopy::SplitAt; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, KnownLayout)] /// #[repr(C)] /// struct Packet<B: ?Sized> { /// length: u8, /// body: B, /// } /// /// let packet: &mut Packet<[u16]> = &mut Packet { length: 4, body: [1u16, 2, 3, 4, 5, 6, 7, 8, 9] }; /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); /// /// // Every body length requires no trailing padding. /// if let Some(split) = packet.split_at_mut(packet.length as usize) { /// let (packet, rest) = split.via_no_dynamic_padding(); /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4]); /// assert_eq!(rest, [5, 6, 7, 8, 9]); /// rest.fill(0); /// } else { /// unreachable!("The packet's length field is within its body"); /// } /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]); /// ``` /// /// # Compile-Time Assertions /// /// This method rejects at compile-time any type that admits dynamic /// trailing padding. In the below example, some `split_at` indices would /// produce left parts whose trailing padding overlaps with the right part: /// /// ```compile_fail,E0080 /// use zerocopy::SplitAt; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, KnownLayout)] /// #[repr(C, align(2))] /// struct Packet<B: ?Sized> { /// length: u16, /// body: B, /// } /// /// let packet: &mut Packet<[u8]> = &mut Packet { length: 4, body: [1u8, 2, 3, 4, 5, 6, 7, 8, 9] }; /// /// if let Some(split) = packet.split_at_mut(packet.length as usize) { /// let _ = split.via_no_dynamic_padding(); // ⚠ Compile Error! /// } else { /// unreachable!("The packet's length field is within its body"); /// } /// ``` /// /// If you need to split such types, use [`Self::via_runtime_check`]. /// /// # Code Generation /// /// See [`Split::via_immutable`](#method.split_via_immutable.codegen). #[must_use = "has no side effects"] #[inline(always)] pub fn via_no_dynamic_padding(self) -> (&'a mut T, &'a mut [T::Elem]) { let (l, r) = self.into_ptr().via_no_dynamic_padding(); (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_no_dynamic_padding`], which perform no runtime check. /// /// # Examples /// /// ``` /// use zerocopy::SplitAt; /// # use zerocopy_derive::*; /// /// #[derive(SplitAt, KnownLayout)] /// #[repr(C, align(2))] /// struct Packet<B: ?Sized> { /// length: u16, /// body: B, /// } /// /// let packet: &mut Packet<[u8]> = &mut Packet { length: 4, body: [1u8, 2, 3, 4, 5, 6, 7, 8, 9] }; /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); /// /// // The two-byte prefix and four-byte body need no trailing padding. /// if let Some(split) = packet.split_at_mut(packet.length as usize) { /// if let Ok((packet, rest)) = split.via_runtime_check() { /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4]); /// assert_eq!(rest, [5, 6, 7, 8, 9]); /// rest.fill(0); /// } else { /// unreachable!("A four-byte body requires no trailing padding"); /// } /// } else { /// unreachable!("The packet's length field is within its body"); /// } /// /// assert_eq!(packet.length, 4); /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]); /// ``` /// /// # Code Generation /// /// See [`Split::via_runtime_check`](#method.split_via_runtime_check.codegen). #[must_use = "has no side effects"] #[inline(always)] pub fn via_runtime_check(self) -> Result<(&'a mut T, &'a mut [T::Elem]), Self> { match self.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. /// /// # Code Generation /// /// See [`Split::via_unchecked`](#method.split_via_unchecked.codegen). #[must_use = "has no side effects"] #[inline(always)] pub unsafe fn 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 = Safe>,{ 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` after the conservative layout /// predicate establishes that `T` never requires dynamic trailing padding. #[inline(always)] fn via_no_dynamic_padding(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) { static_assert!( T: ?Sized + KnownLayout => !T::LAYOUT.requires_dynamic_padding(), "`Split::via_no_dynamic_padding` cannot be used with a type whose layout may require dynamic trailing padding; use `Split::via_runtime_check` instead" );
// SAFETY: The assertion establishes that `requires_dynamic_padding()` // is false. By that method's guarantee, every valid metadata—including // `self.l_len()`, which is valid by `Split`'s invariant—describes an // object with no trailing padding. By the postcondition of // `PtrInner::split_at_unchecked`, the two returned referents are then // contiguous and non-overlapping. Since the source already conforms to // `I::Aliasing`, splitting it into disjoint byte ranges preserves that // invariant: under `Exclusive`, neither result aliases or accesses the // other's bytes; under `Shared`, interior mutation through one result // cannot mutate bytes pointed to by the other. This satisfies Rust's // reference aliasing rules [1]. // // [1] Per https://doc.rust-lang.org/1.93.1/std/ptr/index.html#pointer-to-reference-conversion: // // When creating a mutable reference, then while this reference // exists, the memory it points to must not get accessed (read or // written) through any other pointer or reference not derived from // this reference. // // When creating a shared reference, then while this reference // exists, the memory it points to must not get mutated (except inside // `UnsafeCell`). 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_no_dynamic_padding`], which perform no runtime check. #[inline(always)] fn via_runtime_check(self) -> Result<(Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>), Self> { let l_len = self.l_len(); // `l_len` witnesses an object size at most `isize::MAX`, and // `KnownLayout::LAYOUT` guarantees that it contains the trailing // slice. Thus `padding_for_elems` returns the exact trailing padding. let trailing_padding = crate::trailing_slice_layout::<T>().padding_for_elems(l_len.get()); // 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 trailing_padding == 0 { // SAFETY: As established above, `trailing_padding` is the exact // padding after the left part's trailing slice. If it is zero, // 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 the left part has no trailing padding. #[inline(always)] unsafe fn 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 the left part has no // trailing padding. Consequently, by the postcondition of // `PtrInner::split_at_unchecked`, `left` and `right` do not overlap. // 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`: // if the source is aligned, `T: SplitAt` guarantees that its // trailing slice's address is aligned for `T::Elem`. Advancing by // whole elements preserves that alignment. // 2. `right` conforms to the validity invariant of `I::Validity`, // because `T: SplitAt` guarantees that `T::Elem` has the size and // bit validity of the original trailing element. It also guarantees // compatible shared and mutable access, so writes through `right` // preserve the original elements' validity and interior mutation // respects the original `UnsafeCell` coverage. The left part // cannot invalidate `right`: when the references are exclusive or // permit interior mutation, the caller guarantees no trailing // padding and hence no overlap. let right = unsafe { Ptr::from_inner(right) };
(left, right) }}
#[cfg(test)]mod tests { use core::{cell::Cell, mem::ManuallyDrop};
use crate::{Immutable, KnownLayout, SplitAt, Unalign, Unaligned};
#[derive(KnownLayout, SplitAt, Immutable, Unaligned)] #[repr(C, packed)] struct Packed<T: ?Sized> { prefix: u8, tail: ManuallyDrop<T>, }
#[derive(KnownLayout, SplitAt, Immutable)] #[repr(C, packed(2))] struct Packed2<T: ?Sized> { prefix: u8, tail: ManuallyDrop<T>, }
#[derive(KnownLayout, SplitAt, Immutable)] #[repr(C)] struct Inner<T: ?Sized> { prefix: u32, tail: T, }
#[test] fn test_split_at_packed() { use crate::{FromBytes, IntoBytes};
#[derive(FromBytes, IntoBytes, KnownLayout, SplitAt, Immutable, Unaligned)] #[repr(C, packed)] struct Packet { prefix: u8, tail: [u16], }
// The tail starts at an odd address, exercising unaligned reads and // writes on targets where `u16` has alignment 2. #[repr(align(8))] struct Bytes([u8; 9]);
for i in 0..=4 { let mut bytes = Bytes([1; 9]); let packet = Packet::ref_from_bytes(&bytes.0).unwrap(); let (left, right): (&Packet, &[Unalign<u16>]) = packet.split_at(i).unwrap().via_immutable(); assert_eq!(core::mem::size_of_val(left), 1 + 2 * i); assert_eq!(right.len(), 4 - i); assert!(right.iter().all(|elem| elem.get() == 0x0101)); assert!(left.split_at(i).is_some()); assert!(left.split_at(i + 1).is_none()); assert!(packet.split_at(5).is_none());
let (_, right) = packet.split_at(i).unwrap().via_into_bytes(); assert_eq!(right.len(), 4 - i); let (_, right) = packet.split_at(i).unwrap().via_no_dynamic_padding(); assert_eq!(right.len(), 4 - i);
let packet = Packet::mut_from_bytes(&mut bytes.0).unwrap(); let (left, right): (&mut Packet, &mut [Unalign<u16>]) = packet.split_at_mut(i).unwrap().via_runtime_check().ok().unwrap(); left.prefix = 2; for elem in right { *elem = Unalign::new(0x0202); } assert_eq!(bytes.0[0], 2); assert!(bytes.0[1..1 + 2 * i].iter().all(|&byte| byte == 1)); assert!(bytes.0[1 + 2 * i..].iter().all(|&byte| byte == 2)); } }
#[test] fn test_split_at_nested_packed() { // A packing factor greater than 1 still exposes `Unalign` elements, // including when the factor is below the original element alignment. let mut words = Packed2 { prefix: 0, tail: ManuallyDrop::new([1u32, 2, 3]) }; let dst: &mut Packed2<[u32]> = &mut words; let (left, right): (&mut _, &mut [Unalign<u32>]) = dst.split_at_mut(1).unwrap().via_no_dynamic_padding(); left.prefix = 4; right[0] = Unalign::new(5); let dst: &Packed2<[u32]> = &words; let (left, right) = dst.split_at(0).unwrap().via_immutable(); assert_eq!(left.prefix, 4); assert_eq!(right[0].get(), 1); assert_eq!(right[1].get(), 5); assert_eq!(right[2].get(), 3);
let mut packet = Inner { prefix: 0, tail: Packed2 { prefix: 1, tail: ManuallyDrop::new(Packed { prefix: 2, tail: ManuallyDrop::new([3u16, 4, 5]), }), }, }; let dst: &Inner<Packed2<Packed<[u16]>>> = &packet; let (left, right): (&_, &[Unalign<Unalign<u16>>]) = dst.split_at(1).unwrap().via_immutable(); assert_eq!(left.prefix, 0); assert_eq!(right.len(), 2); assert_eq!(right[0].get().get(), 4); assert_eq!(right[1].get().get(), 5);
// Split the packed field separately: the unpacked outer struct's // padding does not constrain this split. let dst: &mut Packed2<Packed<[u16]>> = &mut packet.tail; let (left, right): (&mut _, &mut [Unalign<Unalign<u16>>]) = dst.split_at_mut(1).unwrap().via_no_dynamic_padding(); left.prefix = 6; right[0] = Unalign::new(Unalign::new(7)); let dst: &Inner<Packed2<Packed<[u16]>>> = &packet; let (_, right) = dst.split_at(0).unwrap().via_immutable(); assert_eq!(right[0].get().get(), 3); assert_eq!(right[1].get().get(), 7); assert_eq!(right[2].get().get(), 5); }
#[test] fn test_split_at_packed_preserves_inner_padding() { for i in 0..=4 { let mut packet = Packed { prefix: 1, tail: ManuallyDrop::new(Inner { prefix: 0, tail: [2u8, 3, 4, 5] }), }; let dst: &Packed<Inner<[u8]>> = &packet; let (left, right): (&_, &[Unalign<u8>]) = dst.split_at(i).unwrap().via_immutable(); assert_eq!(right.len(), 4 - i); assert_eq!(right.first().map(Unalign::get), [2, 3, 4, 5].get(i).copied());
// The inner `u32` prefix makes the tail start at byte 5 of the // packed wrapper. Its size may still include inner padding. let has_padding = core::mem::size_of_val(left) != 5 + i; assert_eq!(dst.split_at(i).unwrap().via_runtime_check().is_err(), has_padding);
let dst: &mut Packed<Inner<[u8]>> = &mut packet; let split = dst.split_at_mut(i).unwrap().via_runtime_check(); assert_eq!(split.is_err(), has_padding); if let Ok((left, right)) = split { left.prefix = 6; for elem in right { *elem = Unalign::new(7); } let dst: &Packed<Inner<[u8]>> = &packet; let (left, right) = dst.split_at(i).unwrap().via_immutable(); assert_eq!(left.prefix, 6); assert!(right.iter().all(|elem| elem.get() == 7)); } } }
#[test] fn test_split_at_packed_interior_mutation_and_zsts() { let packet = Packed { prefix: 0, tail: ManuallyDrop::new([Cell::new(1u8), Cell::new(2), Cell::new(3)]), }; let dst: &Packed<[Cell<u8>]> = &packet; let (left, right): (&_, &[Unalign<Cell<u8>>]) = dst.split_at(1).unwrap().via_no_dynamic_padding(); left.tail[0].set(4); right[0].try_deref().unwrap().set(5); assert_eq!(dst.tail[0].get(), 4); assert_eq!(dst.tail[1].get(), 5); assert_eq!(dst.tail[2].get(), 3);
let mut packet = Packed { prefix: 0, tail: ManuallyDrop::new([(); 3]) }; for i in 0..=3 { let dst: &mut Packed<[()]> = &mut packet; let (left, right): (&mut _, &mut [Unalign<()>]) = dst.split_at_mut(i).unwrap().via_no_dynamic_padding(); assert_eq!(left.tail.len(), i); assert_eq!(right.len(), 3 - i); assert_eq!(core::mem::size_of_val(left), 1); } }
#[cfg(feature = "derive")] #[test] fn test_split_at() { use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt};
#[derive(FromBytes, KnownLayout, SplitAt, IntoBytes, Immutable, Debug)] #[repr(C)] struct SliceDst<const OFFSET: usize> { prefix: [u8; OFFSET], trailing: [u8], }
#[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 in 0..=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; let mut arr = [1; BUFFER_SIZE]; let dst = SliceDst::<OFFSET>::mut_from_bytes(&mut arr[..]).unwrap(); for i in 0..=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); } }
test_split_at::<0, 16>(); test_split_at::<1, 17>(); test_split_at::<2, 18>(); }
#[cfg(feature = "derive")] #[test] #[allow(clippy::as_conversions)] fn test_split_at_overlapping() { use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt};
#[derive(FromBytes, KnownLayout, SplitAt, Immutable)] #[repr(C, align(2))] struct SliceDst { prefix: u8, trailing: [u8], }
assert!(SliceDst::LAYOUT.requires_dynamic_padding());
const N: usize = 16;
let arr = [1u16; N]; let dst = SliceDst::ref_from_bytes(arr.as_bytes()).unwrap();
for i in 0..N { let split = dst.split_at(i).unwrap().via_runtime_check(); if i % 2 == 1 { assert!(split.is_ok()); } else { assert!(split.is_err()); } } } #[test] fn test_split_at_unchecked() { use crate::SplitAt; let mut arr = [1, 2, 3, 4]; let slice = &arr[..]; // SAFETY: 2 <= arr.len() (4) let split = unsafe { SplitAt::split_at_unchecked(slice, 2) }; // SAFETY: SplitAt::split_at_unchecked guarantees that the split is valid. let (l, r) = unsafe { split.via_unchecked() }; assert_eq!(l, &[1, 2]); assert_eq!(r, &[3, 4]);
let slice_mut = &mut arr[..]; // SAFETY: 2 <= arr.len() (4) let split = unsafe { SplitAt::split_at_mut_unchecked(slice_mut, 2) }; // SAFETY: SplitAt::split_at_mut_unchecked guarantees that the split is valid. let (l, r) = unsafe { split.via_unchecked() }; assert_eq!(l, &mut [1, 2]); assert_eq!(r, &mut [3, 4]); }
#[test] fn test_split_at_via_methods() { use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt}; #[derive(FromBytes, KnownLayout, SplitAt, IntoBytes, Immutable, Debug)] #[repr(C)] struct Packet { length: u8, body: [u8], }
let arr = [1, 2, 3, 4]; let packet = Packet::ref_from_bytes(&arr[..]).unwrap();
let split1 = packet.split_at(2).unwrap(); let (l, r) = split1.via_immutable(); assert_eq!(l.length, 1); assert_eq!(r, &[4]);
let split2 = packet.split_at(2).unwrap(); let (l, r) = split2.via_into_bytes(); assert_eq!(l.length, 1); assert_eq!(r, &[4]); } #[test] #[allow(deprecated)] fn test_split_at_via_unaligned() { use crate::{Immutable, KnownLayout, Split, SplitAt, Unaligned};
fn via_unaligned<'a, T>(split: Split<&'a T>) -> (&'a T, &'a [T::Elem]) where T: ?Sized + SplitAt + Unaligned, { split.via_unaligned() }
fn via_unaligned_mut<'a, T>(split: Split<&'a mut T>) -> (&'a mut T, &'a mut [T::Elem]) where T: ?Sized + SplitAt + Unaligned, { split.via_unaligned() }
#[derive(KnownLayout, SplitAt, Immutable, Unaligned)] #[repr(C)] struct Packet<B: ?Sized> { prefix: [u8; 2], body: B, }
// Exercise generic callers using the original `T: Unaligned` bound. assert!(!Packet::<[[u8; 2]]>::LAYOUT.requires_dynamic_padding()); let packet = Packet { prefix: [0, 1], body: [[2, 3], [4, 5], [6, 7]] }; let packet: &Packet<[[u8; 2]]> = &packet;
let split = packet.split_at(2).unwrap(); let (l, r) = via_unaligned(split); assert_eq!(l.body, [[2, 3], [4, 5]]); assert_eq!(r, &[[6, 7]]);
let mut packet = Packet { prefix: [0, 1], body: [[2, 3], [4, 5], [6, 7]] }; { let packet: &mut Packet<[[u8; 2]]> = &mut packet; let split = packet.split_at_mut(2).unwrap(); let (l, r) = via_unaligned_mut(split); l.body[0] = [8, 9]; r[0] = [10, 11]; } assert_eq!(packet.body, [[8, 9], [4, 5], [10, 11]]); }
#[test] fn test_split_at_via_no_dynamic_padding() { use core::cell::Cell;
use crate::SplitAt;
// `u16` does not implement `Unaligned`, but `[u16]` never requires // dynamic trailing padding. let words = [1u16, 2, 3, 4]; let split = SplitAt::split_at(&words[..], 2).unwrap(); let (left, right) = split.via_no_dynamic_padding(); assert_eq!(left, [1, 2]); assert_eq!(right, [3, 4]);
let mut words = [1u16, 2, 3, 4]; let split = SplitAt::split_at_mut(&mut words[..], 2).unwrap(); let (left, right) = split.via_no_dynamic_padding(); left[0] = 5; right[0] = 6; assert_eq!(words, [5, 2, 6, 4]);
// Exercise the safety-sensitive shared route with interior mutation. let cells = [Cell::new(1u16), Cell::new(2), Cell::new(3)]; let split = SplitAt::split_at(&cells[..], 2).unwrap(); let (left, right) = split.via_no_dynamic_padding(); left[0].set(4); right[0].set(5); assert_eq!([cells[0].get(), cells[1].get(), cells[2].get()], [4, 2, 5]); }}