1*c3739801SMiguel Ojeda // Copyright 2025 The Fuchsia Authors 2*c3739801SMiguel Ojeda // 3*c3739801SMiguel Ojeda // Licensed under the 2-Clause BSD License <LICENSE-BSD or 4*c3739801SMiguel Ojeda // https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0 5*c3739801SMiguel Ojeda // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT 6*c3739801SMiguel Ojeda // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option. 7*c3739801SMiguel Ojeda // This file may not be copied, modified, or distributed except according to 8*c3739801SMiguel Ojeda // those terms. 9*c3739801SMiguel Ojeda 10*c3739801SMiguel Ojeda use super::*; 11*c3739801SMiguel Ojeda use crate::pointer::invariant::{Aligned, Exclusive, Invariants, Shared, Valid}; 12*c3739801SMiguel Ojeda 13*c3739801SMiguel Ojeda /// Types that can be split in two. 14*c3739801SMiguel Ojeda /// 15*c3739801SMiguel Ojeda /// This trait generalizes Rust's existing support for splitting slices to 16*c3739801SMiguel Ojeda /// support slices and slice-based dynamically-sized types ("slice DSTs"). 17*c3739801SMiguel Ojeda /// 18*c3739801SMiguel Ojeda /// # Implementation 19*c3739801SMiguel Ojeda /// 20*c3739801SMiguel Ojeda /// **Do not implement this trait yourself!** Instead, use 21*c3739801SMiguel Ojeda /// [`#[derive(SplitAt)]`][derive]; e.g.: 22*c3739801SMiguel Ojeda /// 23*c3739801SMiguel Ojeda /// ``` 24*c3739801SMiguel Ojeda /// # use zerocopy_derive::{SplitAt, KnownLayout}; 25*c3739801SMiguel Ojeda /// #[derive(SplitAt, KnownLayout)] 26*c3739801SMiguel Ojeda /// #[repr(C)] 27*c3739801SMiguel Ojeda /// struct MyStruct<T: ?Sized> { 28*c3739801SMiguel Ojeda /// # /* 29*c3739801SMiguel Ojeda /// ..., 30*c3739801SMiguel Ojeda /// # */ 31*c3739801SMiguel Ojeda /// // `SplitAt` types must have at least one field. 32*c3739801SMiguel Ojeda /// field: T, 33*c3739801SMiguel Ojeda /// } 34*c3739801SMiguel Ojeda /// ``` 35*c3739801SMiguel Ojeda /// 36*c3739801SMiguel Ojeda /// This derive performs a sophisticated, compile-time safety analysis to 37*c3739801SMiguel Ojeda /// determine whether a type is `SplitAt`. 38*c3739801SMiguel Ojeda /// 39*c3739801SMiguel Ojeda /// # Safety 40*c3739801SMiguel Ojeda /// 41*c3739801SMiguel Ojeda /// This trait does not convey any safety guarantees to code outside this crate. 42*c3739801SMiguel Ojeda /// 43*c3739801SMiguel Ojeda /// You must not rely on the `#[doc(hidden)]` internals of `SplitAt`. Future 44*c3739801SMiguel Ojeda /// releases of zerocopy may make backwards-breaking changes to these items, 45*c3739801SMiguel Ojeda /// including changes that only affect soundness, which may cause code which 46*c3739801SMiguel Ojeda /// uses those items to silently become unsound. 47*c3739801SMiguel Ojeda /// 48*c3739801SMiguel Ojeda #[cfg_attr(feature = "derive", doc = "[derive]: zerocopy_derive::SplitAt")] 49*c3739801SMiguel Ojeda #[cfg_attr( 50*c3739801SMiguel Ojeda not(feature = "derive"), 51*c3739801SMiguel Ojeda doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.SplitAt.html"), 52*c3739801SMiguel Ojeda )] 53*c3739801SMiguel Ojeda #[cfg_attr( 54*c3739801SMiguel Ojeda not(no_zerocopy_diagnostic_on_unimplemented_1_78_0), 55*c3739801SMiguel Ojeda diagnostic::on_unimplemented(note = "Consider adding `#[derive(SplitAt)]` to `{Self}`") 56*c3739801SMiguel Ojeda )] 57*c3739801SMiguel Ojeda // # Safety 58*c3739801SMiguel Ojeda // 59*c3739801SMiguel Ojeda // The trailing slice is well-aligned for its element type. `Self` is `[T]`, or 60*c3739801SMiguel Ojeda // a `repr(C)` or `repr(transparent)` slice DST. 61*c3739801SMiguel Ojeda pub unsafe trait SplitAt: KnownLayout<PointerMetadata = usize> { 62*c3739801SMiguel Ojeda /// The element type of the trailing slice. 63*c3739801SMiguel Ojeda type Elem; 64*c3739801SMiguel Ojeda 65*c3739801SMiguel Ojeda #[doc(hidden)] 66*c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 67*c3739801SMiguel Ojeda where 68*c3739801SMiguel Ojeda Self: Sized; 69*c3739801SMiguel Ojeda 70*c3739801SMiguel Ojeda /// Unsafely splits `self` in two. 71*c3739801SMiguel Ojeda /// 72*c3739801SMiguel Ojeda /// # Safety 73*c3739801SMiguel Ojeda /// 74*c3739801SMiguel Ojeda /// The caller promises that `l_len` is not greater than the length of 75*c3739801SMiguel Ojeda /// `self`'s trailing slice. 76*c3739801SMiguel Ojeda /// 77*c3739801SMiguel Ojeda #[doc = codegen_section!( 78*c3739801SMiguel Ojeda header = "h5", 79*c3739801SMiguel Ojeda bench = "split_at_unchecked", 80*c3739801SMiguel Ojeda format = "coco", 81*c3739801SMiguel Ojeda arity = 2, 82*c3739801SMiguel Ojeda [ 83*c3739801SMiguel Ojeda open 84*c3739801SMiguel Ojeda @index 1 85*c3739801SMiguel Ojeda @title "Unsized" 86*c3739801SMiguel Ojeda @variant "dynamic_size" 87*c3739801SMiguel Ojeda ], 88*c3739801SMiguel Ojeda [ 89*c3739801SMiguel Ojeda @index 2 90*c3739801SMiguel Ojeda @title "Dynamically Padded" 91*c3739801SMiguel Ojeda @variant "dynamic_padding" 92*c3739801SMiguel Ojeda ] 93*c3739801SMiguel Ojeda )] 94*c3739801SMiguel Ojeda #[inline] 95*c3739801SMiguel Ojeda #[must_use] 96*c3739801SMiguel Ojeda unsafe fn split_at_unchecked(&self, l_len: usize) -> Split<&Self> { 97*c3739801SMiguel Ojeda // SAFETY: By precondition on the caller, `l_len <= self.len()`. 98*c3739801SMiguel Ojeda unsafe { Split::<&Self>::new(self, l_len) } 99*c3739801SMiguel Ojeda } 100*c3739801SMiguel Ojeda 101*c3739801SMiguel Ojeda /// Attempts to split `self` in two. 102*c3739801SMiguel Ojeda /// 103*c3739801SMiguel Ojeda /// Returns `None` if `l_len` is greater than the length of `self`'s 104*c3739801SMiguel Ojeda /// trailing slice. 105*c3739801SMiguel Ojeda /// 106*c3739801SMiguel Ojeda /// # Examples 107*c3739801SMiguel Ojeda /// 108*c3739801SMiguel Ojeda /// ``` 109*c3739801SMiguel Ojeda /// use zerocopy::{SplitAt, FromBytes}; 110*c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 111*c3739801SMiguel Ojeda /// 112*c3739801SMiguel Ojeda /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable)] 113*c3739801SMiguel Ojeda /// #[repr(C)] 114*c3739801SMiguel Ojeda /// struct Packet { 115*c3739801SMiguel Ojeda /// length: u8, 116*c3739801SMiguel Ojeda /// body: [u8], 117*c3739801SMiguel Ojeda /// } 118*c3739801SMiguel Ojeda /// 119*c3739801SMiguel Ojeda /// // These bytes encode a `Packet`. 120*c3739801SMiguel Ojeda /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 121*c3739801SMiguel Ojeda /// 122*c3739801SMiguel Ojeda /// let packet = Packet::ref_from_bytes(bytes).unwrap(); 123*c3739801SMiguel Ojeda /// 124*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 125*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); 126*c3739801SMiguel Ojeda /// 127*c3739801SMiguel Ojeda /// // Attempt to split `packet` at `length`. 128*c3739801SMiguel Ojeda /// let split = packet.split_at(packet.length as usize).unwrap(); 129*c3739801SMiguel Ojeda /// 130*c3739801SMiguel Ojeda /// // Use the `Immutable` bound on `Packet` to prove that it's okay to 131*c3739801SMiguel Ojeda /// // return concurrent references to `packet` and `rest`. 132*c3739801SMiguel Ojeda /// let (packet, rest) = split.via_immutable(); 133*c3739801SMiguel Ojeda /// 134*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 135*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4]); 136*c3739801SMiguel Ojeda /// assert_eq!(rest, [5, 6, 7, 8, 9]); 137*c3739801SMiguel Ojeda /// ``` 138*c3739801SMiguel Ojeda /// 139*c3739801SMiguel Ojeda #[doc = codegen_section!( 140*c3739801SMiguel Ojeda header = "h5", 141*c3739801SMiguel Ojeda bench = "split_at", 142*c3739801SMiguel Ojeda format = "coco", 143*c3739801SMiguel Ojeda arity = 2, 144*c3739801SMiguel Ojeda [ 145*c3739801SMiguel Ojeda open 146*c3739801SMiguel Ojeda @index 1 147*c3739801SMiguel Ojeda @title "Unsized" 148*c3739801SMiguel Ojeda @variant "dynamic_size" 149*c3739801SMiguel Ojeda ], 150*c3739801SMiguel Ojeda [ 151*c3739801SMiguel Ojeda @index 2 152*c3739801SMiguel Ojeda @title "Dynamically Padded" 153*c3739801SMiguel Ojeda @variant "dynamic_padding" 154*c3739801SMiguel Ojeda ] 155*c3739801SMiguel Ojeda )] 156*c3739801SMiguel Ojeda #[inline] 157*c3739801SMiguel Ojeda #[must_use = "has no side effects"] 158*c3739801SMiguel Ojeda fn split_at(&self, l_len: usize) -> Option<Split<&Self>> { 159*c3739801SMiguel Ojeda MetadataOf::new_in_bounds(self, l_len).map( 160*c3739801SMiguel Ojeda #[inline(always)] 161*c3739801SMiguel Ojeda |l_len| { 162*c3739801SMiguel Ojeda // SAFETY: We have ensured that `l_len <= self.len()` (by 163*c3739801SMiguel Ojeda // post-condition on `MetadataOf::new_in_bounds`) 164*c3739801SMiguel Ojeda unsafe { Split::new(self, l_len.get()) } 165*c3739801SMiguel Ojeda }, 166*c3739801SMiguel Ojeda ) 167*c3739801SMiguel Ojeda } 168*c3739801SMiguel Ojeda 169*c3739801SMiguel Ojeda /// Unsafely splits `self` in two. 170*c3739801SMiguel Ojeda /// 171*c3739801SMiguel Ojeda /// # Safety 172*c3739801SMiguel Ojeda /// 173*c3739801SMiguel Ojeda /// The caller promises that `l_len` is not greater than the length of 174*c3739801SMiguel Ojeda /// `self`'s trailing slice. 175*c3739801SMiguel Ojeda /// 176*c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "split_at_mut_unchecked")] 177*c3739801SMiguel Ojeda /// 178*c3739801SMiguel Ojeda /// See [`SplitAt::split_at_unchecked`](#method.split_at_unchecked.codegen). 179*c3739801SMiguel Ojeda #[inline] 180*c3739801SMiguel Ojeda #[must_use] 181*c3739801SMiguel Ojeda unsafe fn split_at_mut_unchecked(&mut self, l_len: usize) -> Split<&mut Self> { 182*c3739801SMiguel Ojeda // SAFETY: By precondition on the caller, `l_len <= self.len()`. 183*c3739801SMiguel Ojeda unsafe { Split::<&mut Self>::new(self, l_len) } 184*c3739801SMiguel Ojeda } 185*c3739801SMiguel Ojeda 186*c3739801SMiguel Ojeda /// Attempts to split `self` in two. 187*c3739801SMiguel Ojeda /// 188*c3739801SMiguel Ojeda /// Returns `None` if `l_len` is greater than the length of `self`'s 189*c3739801SMiguel Ojeda /// trailing slice, or if the given `l_len` would result in [the trailing 190*c3739801SMiguel Ojeda /// padding](KnownLayout#slice-dst-layout) of the left portion overlapping 191*c3739801SMiguel Ojeda /// the right portion. 192*c3739801SMiguel Ojeda /// 193*c3739801SMiguel Ojeda /// 194*c3739801SMiguel Ojeda /// # Examples 195*c3739801SMiguel Ojeda /// 196*c3739801SMiguel Ojeda /// ``` 197*c3739801SMiguel Ojeda /// use zerocopy::{SplitAt, FromBytes}; 198*c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 199*c3739801SMiguel Ojeda /// 200*c3739801SMiguel Ojeda /// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes)] 201*c3739801SMiguel Ojeda /// #[repr(C)] 202*c3739801SMiguel Ojeda /// struct Packet<B: ?Sized> { 203*c3739801SMiguel Ojeda /// length: u8, 204*c3739801SMiguel Ojeda /// body: B, 205*c3739801SMiguel Ojeda /// } 206*c3739801SMiguel Ojeda /// 207*c3739801SMiguel Ojeda /// // These bytes encode a `Packet`. 208*c3739801SMiguel Ojeda /// let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 209*c3739801SMiguel Ojeda /// 210*c3739801SMiguel Ojeda /// let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap(); 211*c3739801SMiguel Ojeda /// 212*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 213*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); 214*c3739801SMiguel Ojeda /// 215*c3739801SMiguel Ojeda /// { 216*c3739801SMiguel Ojeda /// // Attempt to split `packet` at `length`. 217*c3739801SMiguel Ojeda /// let split = packet.split_at_mut(packet.length as usize).unwrap(); 218*c3739801SMiguel Ojeda /// 219*c3739801SMiguel Ojeda /// // Use the `IntoBytes` bound on `Packet` to prove that it's okay to 220*c3739801SMiguel Ojeda /// // return concurrent references to `packet` and `rest`. 221*c3739801SMiguel Ojeda /// let (packet, rest) = split.via_into_bytes(); 222*c3739801SMiguel Ojeda /// 223*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 224*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4]); 225*c3739801SMiguel Ojeda /// assert_eq!(rest, [5, 6, 7, 8, 9]); 226*c3739801SMiguel Ojeda /// 227*c3739801SMiguel Ojeda /// rest.fill(0); 228*c3739801SMiguel Ojeda /// } 229*c3739801SMiguel Ojeda /// 230*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 231*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]); 232*c3739801SMiguel Ojeda /// ``` 233*c3739801SMiguel Ojeda /// 234*c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "split_at_mut")] 235*c3739801SMiguel Ojeda /// 236*c3739801SMiguel Ojeda /// See [`SplitAt::split_at`](#method.split_at.codegen). 237*c3739801SMiguel Ojeda #[inline] 238*c3739801SMiguel Ojeda fn split_at_mut(&mut self, l_len: usize) -> Option<Split<&mut Self>> { 239*c3739801SMiguel Ojeda MetadataOf::new_in_bounds(self, l_len).map( 240*c3739801SMiguel Ojeda #[inline(always)] 241*c3739801SMiguel Ojeda |l_len| { 242*c3739801SMiguel Ojeda // SAFETY: We have ensured that `l_len <= self.len()` (by 243*c3739801SMiguel Ojeda // post-condition on `MetadataOf::new_in_bounds`) 244*c3739801SMiguel Ojeda unsafe { Split::new(self, l_len.get()) } 245*c3739801SMiguel Ojeda }, 246*c3739801SMiguel Ojeda ) 247*c3739801SMiguel Ojeda } 248*c3739801SMiguel Ojeda } 249*c3739801SMiguel Ojeda 250*c3739801SMiguel Ojeda // SAFETY: `[T]`'s trailing slice is `[T]`, which is trivially aligned. 251*c3739801SMiguel Ojeda unsafe impl<T> SplitAt for [T] { 252*c3739801SMiguel Ojeda type Elem = T; 253*c3739801SMiguel Ojeda 254*c3739801SMiguel Ojeda #[inline] 255*c3739801SMiguel Ojeda #[allow(dead_code)] 256*c3739801SMiguel Ojeda fn only_derive_is_allowed_to_implement_this_trait() 257*c3739801SMiguel Ojeda where 258*c3739801SMiguel Ojeda Self: Sized, 259*c3739801SMiguel Ojeda { 260*c3739801SMiguel Ojeda } 261*c3739801SMiguel Ojeda } 262*c3739801SMiguel Ojeda 263*c3739801SMiguel Ojeda /// A `T` that has been split into two possibly-overlapping parts. 264*c3739801SMiguel Ojeda /// 265*c3739801SMiguel Ojeda /// For some dynamically sized types, the padding that appears after the 266*c3739801SMiguel Ojeda /// trailing slice field [is a dynamic function of the trailing slice 267*c3739801SMiguel Ojeda /// length](KnownLayout#slice-dst-layout). If `T` is split at a length that 268*c3739801SMiguel Ojeda /// requires trailing padding, the trailing padding of the left part of the 269*c3739801SMiguel Ojeda /// split `T` will overlap the right part. If `T` is a mutable reference or 270*c3739801SMiguel Ojeda /// permits interior mutation, you must ensure that the left and right parts do 271*c3739801SMiguel Ojeda /// not overlap. You can do this at zero-cost using using 272*c3739801SMiguel Ojeda /// [`Self::via_immutable`], [`Self::via_into_bytes`], or 273*c3739801SMiguel Ojeda /// [`Self::via_unaligned`], or with a dynamic check by using 274*c3739801SMiguel Ojeda /// [`Self::via_runtime_check`]. 275*c3739801SMiguel Ojeda #[derive(Debug)] 276*c3739801SMiguel Ojeda pub struct Split<T> { 277*c3739801SMiguel Ojeda /// A pointer to the source slice DST. 278*c3739801SMiguel Ojeda source: T, 279*c3739801SMiguel Ojeda /// The length of the future left half of `source`. 280*c3739801SMiguel Ojeda /// 281*c3739801SMiguel Ojeda /// # Safety 282*c3739801SMiguel Ojeda /// 283*c3739801SMiguel Ojeda /// If `source` is a pointer to a slice DST, `l_len` is no greater than 284*c3739801SMiguel Ojeda /// `source`'s length. 285*c3739801SMiguel Ojeda l_len: usize, 286*c3739801SMiguel Ojeda } 287*c3739801SMiguel Ojeda 288*c3739801SMiguel Ojeda impl<T> Split<T> { 289*c3739801SMiguel Ojeda /// Produces a `Split` of `source` with `l_len`. 290*c3739801SMiguel Ojeda /// 291*c3739801SMiguel Ojeda /// # Safety 292*c3739801SMiguel Ojeda /// 293*c3739801SMiguel Ojeda /// `l_len` is no greater than `source`'s length. 294*c3739801SMiguel Ojeda #[inline(always)] 295*c3739801SMiguel Ojeda unsafe fn new(source: T, l_len: usize) -> Self { 296*c3739801SMiguel Ojeda Self { source, l_len } 297*c3739801SMiguel Ojeda } 298*c3739801SMiguel Ojeda } 299*c3739801SMiguel Ojeda 300*c3739801SMiguel Ojeda impl<'a, T> Split<&'a T> 301*c3739801SMiguel Ojeda where 302*c3739801SMiguel Ojeda T: ?Sized + SplitAt, 303*c3739801SMiguel Ojeda { 304*c3739801SMiguel Ojeda #[inline(always)] 305*c3739801SMiguel Ojeda fn into_ptr(self) -> Split<Ptr<'a, T, (Shared, Aligned, Valid)>> { 306*c3739801SMiguel Ojeda let source = Ptr::from_ref(self.source); 307*c3739801SMiguel Ojeda // SAFETY: `Ptr::from_ref(self.source)` points to exactly `self.source` 308*c3739801SMiguel Ojeda // and thus maintains the invariants of `self` with respect to `l_len`. 309*c3739801SMiguel Ojeda unsafe { Split::new(source, self.l_len) } 310*c3739801SMiguel Ojeda } 311*c3739801SMiguel Ojeda 312*c3739801SMiguel Ojeda /// Produces the split parts of `self`, using [`Immutable`] to ensure that 313*c3739801SMiguel Ojeda /// it is sound to have concurrent references to both parts. 314*c3739801SMiguel Ojeda /// 315*c3739801SMiguel Ojeda /// # Examples 316*c3739801SMiguel Ojeda /// 317*c3739801SMiguel Ojeda /// ``` 318*c3739801SMiguel Ojeda /// use zerocopy::{SplitAt, FromBytes}; 319*c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 320*c3739801SMiguel Ojeda /// 321*c3739801SMiguel Ojeda /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable)] 322*c3739801SMiguel Ojeda /// #[repr(C)] 323*c3739801SMiguel Ojeda /// struct Packet { 324*c3739801SMiguel Ojeda /// length: u8, 325*c3739801SMiguel Ojeda /// body: [u8], 326*c3739801SMiguel Ojeda /// } 327*c3739801SMiguel Ojeda /// 328*c3739801SMiguel Ojeda /// // These bytes encode a `Packet`. 329*c3739801SMiguel Ojeda /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 330*c3739801SMiguel Ojeda /// 331*c3739801SMiguel Ojeda /// let packet = Packet::ref_from_bytes(bytes).unwrap(); 332*c3739801SMiguel Ojeda /// 333*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 334*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); 335*c3739801SMiguel Ojeda /// 336*c3739801SMiguel Ojeda /// // Attempt to split `packet` at `length`. 337*c3739801SMiguel Ojeda /// let split = packet.split_at(packet.length as usize).unwrap(); 338*c3739801SMiguel Ojeda /// 339*c3739801SMiguel Ojeda /// // Use the `Immutable` bound on `Packet` to prove that it's okay to 340*c3739801SMiguel Ojeda /// // return concurrent references to `packet` and `rest`. 341*c3739801SMiguel Ojeda /// let (packet, rest) = split.via_immutable(); 342*c3739801SMiguel Ojeda /// 343*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 344*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4]); 345*c3739801SMiguel Ojeda /// assert_eq!(rest, [5, 6, 7, 8, 9]); 346*c3739801SMiguel Ojeda /// ``` 347*c3739801SMiguel Ojeda /// 348*c3739801SMiguel Ojeda #[doc = codegen_section!( 349*c3739801SMiguel Ojeda header = "h5", 350*c3739801SMiguel Ojeda bench = "split_via_immutable", 351*c3739801SMiguel Ojeda format = "coco", 352*c3739801SMiguel Ojeda arity = 2, 353*c3739801SMiguel Ojeda [ 354*c3739801SMiguel Ojeda open 355*c3739801SMiguel Ojeda @index 1 356*c3739801SMiguel Ojeda @title "Unsized" 357*c3739801SMiguel Ojeda @variant "dynamic_size" 358*c3739801SMiguel Ojeda ], 359*c3739801SMiguel Ojeda [ 360*c3739801SMiguel Ojeda @index 2 361*c3739801SMiguel Ojeda @title "Dynamically Padded" 362*c3739801SMiguel Ojeda @variant "dynamic_padding" 363*c3739801SMiguel Ojeda ] 364*c3739801SMiguel Ojeda )] 365*c3739801SMiguel Ojeda #[must_use = "has no side effects"] 366*c3739801SMiguel Ojeda #[inline(always)] 367*c3739801SMiguel Ojeda pub fn via_immutable(self) -> (&'a T, &'a [T::Elem]) 368*c3739801SMiguel Ojeda where 369*c3739801SMiguel Ojeda T: Immutable, 370*c3739801SMiguel Ojeda { 371*c3739801SMiguel Ojeda let (l, r) = self.into_ptr().via_immutable(); 372*c3739801SMiguel Ojeda (l.as_ref(), r.as_ref()) 373*c3739801SMiguel Ojeda } 374*c3739801SMiguel Ojeda 375*c3739801SMiguel Ojeda /// Produces the split parts of `self`, using [`IntoBytes`] to ensure that 376*c3739801SMiguel Ojeda /// it is sound to have concurrent references to both parts. 377*c3739801SMiguel Ojeda /// 378*c3739801SMiguel Ojeda /// # Examples 379*c3739801SMiguel Ojeda /// 380*c3739801SMiguel Ojeda /// ``` 381*c3739801SMiguel Ojeda /// use zerocopy::{SplitAt, FromBytes}; 382*c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 383*c3739801SMiguel Ojeda /// 384*c3739801SMiguel Ojeda /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable, IntoBytes)] 385*c3739801SMiguel Ojeda /// #[repr(C)] 386*c3739801SMiguel Ojeda /// struct Packet<B: ?Sized> { 387*c3739801SMiguel Ojeda /// length: u8, 388*c3739801SMiguel Ojeda /// body: B, 389*c3739801SMiguel Ojeda /// } 390*c3739801SMiguel Ojeda /// 391*c3739801SMiguel Ojeda /// // These bytes encode a `Packet`. 392*c3739801SMiguel Ojeda /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 393*c3739801SMiguel Ojeda /// 394*c3739801SMiguel Ojeda /// let packet = Packet::<[u8]>::ref_from_bytes(bytes).unwrap(); 395*c3739801SMiguel Ojeda /// 396*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 397*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); 398*c3739801SMiguel Ojeda /// 399*c3739801SMiguel Ojeda /// // Attempt to split `packet` at `length`. 400*c3739801SMiguel Ojeda /// let split = packet.split_at(packet.length as usize).unwrap(); 401*c3739801SMiguel Ojeda /// 402*c3739801SMiguel Ojeda /// // Use the `IntoBytes` bound on `Packet` to prove that it's okay to 403*c3739801SMiguel Ojeda /// // return concurrent references to `packet` and `rest`. 404*c3739801SMiguel Ojeda /// let (packet, rest) = split.via_into_bytes(); 405*c3739801SMiguel Ojeda /// 406*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 407*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4]); 408*c3739801SMiguel Ojeda /// assert_eq!(rest, [5, 6, 7, 8, 9]); 409*c3739801SMiguel Ojeda /// ``` 410*c3739801SMiguel Ojeda /// 411*c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "split_via_into_bytes")] 412*c3739801SMiguel Ojeda /// 413*c3739801SMiguel Ojeda /// See [`Split::via_immutable`](#method.split_via_immutable.codegen). 414*c3739801SMiguel Ojeda #[must_use = "has no side effects"] 415*c3739801SMiguel Ojeda #[inline(always)] 416*c3739801SMiguel Ojeda pub fn via_into_bytes(self) -> (&'a T, &'a [T::Elem]) 417*c3739801SMiguel Ojeda where 418*c3739801SMiguel Ojeda T: IntoBytes, 419*c3739801SMiguel Ojeda { 420*c3739801SMiguel Ojeda let (l, r) = self.into_ptr().via_into_bytes(); 421*c3739801SMiguel Ojeda (l.as_ref(), r.as_ref()) 422*c3739801SMiguel Ojeda } 423*c3739801SMiguel Ojeda 424*c3739801SMiguel Ojeda /// Produces the split parts of `self`, using [`Unaligned`] to ensure that 425*c3739801SMiguel Ojeda /// it is sound to have concurrent references to both parts. 426*c3739801SMiguel Ojeda /// 427*c3739801SMiguel Ojeda /// # Examples 428*c3739801SMiguel Ojeda /// 429*c3739801SMiguel Ojeda /// ``` 430*c3739801SMiguel Ojeda /// use zerocopy::{SplitAt, FromBytes}; 431*c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 432*c3739801SMiguel Ojeda /// 433*c3739801SMiguel Ojeda /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable, Unaligned)] 434*c3739801SMiguel Ojeda /// #[repr(C)] 435*c3739801SMiguel Ojeda /// struct Packet { 436*c3739801SMiguel Ojeda /// length: u8, 437*c3739801SMiguel Ojeda /// body: [u8], 438*c3739801SMiguel Ojeda /// } 439*c3739801SMiguel Ojeda /// 440*c3739801SMiguel Ojeda /// // These bytes encode a `Packet`. 441*c3739801SMiguel Ojeda /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 442*c3739801SMiguel Ojeda /// 443*c3739801SMiguel Ojeda /// let packet = Packet::ref_from_bytes(bytes).unwrap(); 444*c3739801SMiguel Ojeda /// 445*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 446*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); 447*c3739801SMiguel Ojeda /// 448*c3739801SMiguel Ojeda /// // Attempt to split `packet` at `length`. 449*c3739801SMiguel Ojeda /// let split = packet.split_at(packet.length as usize).unwrap(); 450*c3739801SMiguel Ojeda /// 451*c3739801SMiguel Ojeda /// // Use the `Unaligned` bound on `Packet` to prove that it's okay to 452*c3739801SMiguel Ojeda /// // return concurrent references to `packet` and `rest`. 453*c3739801SMiguel Ojeda /// let (packet, rest) = split.via_unaligned(); 454*c3739801SMiguel Ojeda /// 455*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 456*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4]); 457*c3739801SMiguel Ojeda /// assert_eq!(rest, [5, 6, 7, 8, 9]); 458*c3739801SMiguel Ojeda /// ``` 459*c3739801SMiguel Ojeda /// 460*c3739801SMiguel Ojeda #[doc = codegen_header!("h5", "split_via_unaligned")] 461*c3739801SMiguel Ojeda /// 462*c3739801SMiguel Ojeda /// See [`Split::via_immutable`](#method.split_via_immutable.codegen). 463*c3739801SMiguel Ojeda #[must_use = "has no side effects"] 464*c3739801SMiguel Ojeda #[inline(always)] 465*c3739801SMiguel Ojeda pub fn via_unaligned(self) -> (&'a T, &'a [T::Elem]) 466*c3739801SMiguel Ojeda where 467*c3739801SMiguel Ojeda T: Unaligned, 468*c3739801SMiguel Ojeda { 469*c3739801SMiguel Ojeda let (l, r) = self.into_ptr().via_unaligned(); 470*c3739801SMiguel Ojeda (l.as_ref(), r.as_ref()) 471*c3739801SMiguel Ojeda } 472*c3739801SMiguel Ojeda 473*c3739801SMiguel Ojeda /// Produces the split parts of `self`, using a dynamic check to ensure that 474*c3739801SMiguel Ojeda /// it is sound to have concurrent references to both parts. You should 475*c3739801SMiguel Ojeda /// prefer using [`Self::via_immutable`], [`Self::via_into_bytes`], or 476*c3739801SMiguel Ojeda /// [`Self::via_unaligned`], which have no runtime cost. 477*c3739801SMiguel Ojeda /// 478*c3739801SMiguel Ojeda /// Note that this check is overly conservative if `T` is [`Immutable`]; for 479*c3739801SMiguel Ojeda /// some types, this check will reject some splits which 480*c3739801SMiguel Ojeda /// [`Self::via_immutable`] will accept. 481*c3739801SMiguel Ojeda /// 482*c3739801SMiguel Ojeda /// # Examples 483*c3739801SMiguel Ojeda /// 484*c3739801SMiguel Ojeda /// ``` 485*c3739801SMiguel Ojeda /// use zerocopy::{SplitAt, FromBytes, IntoBytes, network_endian::U16}; 486*c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 487*c3739801SMiguel Ojeda /// 488*c3739801SMiguel Ojeda /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable, Debug)] 489*c3739801SMiguel Ojeda /// #[repr(C, align(2))] 490*c3739801SMiguel Ojeda /// struct Packet { 491*c3739801SMiguel Ojeda /// length: U16, 492*c3739801SMiguel Ojeda /// body: [u8], 493*c3739801SMiguel Ojeda /// } 494*c3739801SMiguel Ojeda /// 495*c3739801SMiguel Ojeda /// // These bytes encode a `Packet`. 496*c3739801SMiguel Ojeda /// let bytes = [ 497*c3739801SMiguel Ojeda /// 4u16.to_be(), 498*c3739801SMiguel Ojeda /// 1u16.to_be(), 499*c3739801SMiguel Ojeda /// 2u16.to_be(), 500*c3739801SMiguel Ojeda /// 3u16.to_be(), 501*c3739801SMiguel Ojeda /// 4u16.to_be() 502*c3739801SMiguel Ojeda /// ]; 503*c3739801SMiguel Ojeda /// 504*c3739801SMiguel Ojeda /// let packet = Packet::ref_from_bytes(bytes.as_bytes()).unwrap(); 505*c3739801SMiguel Ojeda /// 506*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 507*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [0, 1, 0, 2, 0, 3, 0, 4]); 508*c3739801SMiguel Ojeda /// 509*c3739801SMiguel Ojeda /// // Attempt to split `packet` at `length`. 510*c3739801SMiguel Ojeda /// let split = packet.split_at(packet.length.into()).unwrap(); 511*c3739801SMiguel Ojeda /// 512*c3739801SMiguel Ojeda /// // Use a dynamic check to prove that it's okay to return concurrent 513*c3739801SMiguel Ojeda /// // references to `packet` and `rest`. 514*c3739801SMiguel Ojeda /// let (packet, rest) = split.via_runtime_check().unwrap(); 515*c3739801SMiguel Ojeda /// 516*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 517*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [0, 1, 0, 2]); 518*c3739801SMiguel Ojeda /// assert_eq!(rest, [0, 3, 0, 4]); 519*c3739801SMiguel Ojeda /// 520*c3739801SMiguel Ojeda /// // Attempt to split `packet` at `length - 1`. 521*c3739801SMiguel Ojeda /// let idx = packet.length.get() - 1; 522*c3739801SMiguel Ojeda /// let split = packet.split_at(idx as usize).unwrap(); 523*c3739801SMiguel Ojeda /// 524*c3739801SMiguel Ojeda /// // Attempt (and fail) to use a dynamic check to prove that it's okay 525*c3739801SMiguel Ojeda /// // to return concurrent references to `packet` and `rest`. Note that 526*c3739801SMiguel Ojeda /// // this is a case of `via_runtime_check` being overly conservative. 527*c3739801SMiguel Ojeda /// // Although the left and right parts indeed overlap, the `Immutable` 528*c3739801SMiguel Ojeda /// // bound ensures that concurrently referencing these overlapping 529*c3739801SMiguel Ojeda /// // parts is sound. 530*c3739801SMiguel Ojeda /// assert!(split.via_runtime_check().is_err()); 531*c3739801SMiguel Ojeda /// ``` 532*c3739801SMiguel Ojeda /// 533*c3739801SMiguel Ojeda #[doc = codegen_section!( 534*c3739801SMiguel Ojeda header = "h5", 535*c3739801SMiguel Ojeda bench = "split_via_runtime_check", 536*c3739801SMiguel Ojeda format = "coco", 537*c3739801SMiguel Ojeda arity = 2, 538*c3739801SMiguel Ojeda [ 539*c3739801SMiguel Ojeda open 540*c3739801SMiguel Ojeda @index 1 541*c3739801SMiguel Ojeda @title "Unsized" 542*c3739801SMiguel Ojeda @variant "dynamic_size" 543*c3739801SMiguel Ojeda ], 544*c3739801SMiguel Ojeda [ 545*c3739801SMiguel Ojeda @index 2 546*c3739801SMiguel Ojeda @title "Dynamically Padded" 547*c3739801SMiguel Ojeda @variant "dynamic_padding" 548*c3739801SMiguel Ojeda ] 549*c3739801SMiguel Ojeda )] 550*c3739801SMiguel Ojeda #[must_use = "has no side effects"] 551*c3739801SMiguel Ojeda #[inline(always)] 552*c3739801SMiguel Ojeda pub fn via_runtime_check(self) -> Result<(&'a T, &'a [T::Elem]), Self> { 553*c3739801SMiguel Ojeda match self.into_ptr().via_runtime_check() { 554*c3739801SMiguel Ojeda Ok((l, r)) => Ok((l.as_ref(), r.as_ref())), 555*c3739801SMiguel Ojeda Err(s) => Err(s.into_ref()), 556*c3739801SMiguel Ojeda } 557*c3739801SMiguel Ojeda } 558*c3739801SMiguel Ojeda 559*c3739801SMiguel Ojeda /// Unsafely produces the split parts of `self`. 560*c3739801SMiguel Ojeda /// 561*c3739801SMiguel Ojeda /// # Safety 562*c3739801SMiguel Ojeda /// 563*c3739801SMiguel Ojeda /// If `T` permits interior mutation, the trailing padding bytes of the left 564*c3739801SMiguel Ojeda /// portion must not overlap the right portion. For some dynamically sized 565*c3739801SMiguel Ojeda /// types, the padding that appears after the trailing slice field [is a 566*c3739801SMiguel Ojeda /// dynamic function of the trailing slice 567*c3739801SMiguel Ojeda /// length](KnownLayout#slice-dst-layout). Thus, for some types, this 568*c3739801SMiguel Ojeda /// condition is dependent on the length of the left portion. 569*c3739801SMiguel Ojeda /// 570*c3739801SMiguel Ojeda #[doc = codegen_section!( 571*c3739801SMiguel Ojeda header = "h5", 572*c3739801SMiguel Ojeda bench = "split_via_unchecked", 573*c3739801SMiguel Ojeda format = "coco", 574*c3739801SMiguel Ojeda arity = 2, 575*c3739801SMiguel Ojeda [ 576*c3739801SMiguel Ojeda open 577*c3739801SMiguel Ojeda @index 1 578*c3739801SMiguel Ojeda @title "Unsized" 579*c3739801SMiguel Ojeda @variant "dynamic_size" 580*c3739801SMiguel Ojeda ], 581*c3739801SMiguel Ojeda [ 582*c3739801SMiguel Ojeda @index 2 583*c3739801SMiguel Ojeda @title "Dynamically Padded" 584*c3739801SMiguel Ojeda @variant "dynamic_padding" 585*c3739801SMiguel Ojeda ] 586*c3739801SMiguel Ojeda )] 587*c3739801SMiguel Ojeda #[must_use = "has no side effects"] 588*c3739801SMiguel Ojeda #[inline(always)] 589*c3739801SMiguel Ojeda pub unsafe fn via_unchecked(self) -> (&'a T, &'a [T::Elem]) { 590*c3739801SMiguel Ojeda // SAFETY: The aliasing of `self.into_ptr()` is not `Exclusive`, but the 591*c3739801SMiguel Ojeda // caller has promised that if `T` permits interior mutation then the 592*c3739801SMiguel Ojeda // left and right portions of `self` split at `l_len` do not overlap. 593*c3739801SMiguel Ojeda let (l, r) = unsafe { self.into_ptr().via_unchecked() }; 594*c3739801SMiguel Ojeda (l.as_ref(), r.as_ref()) 595*c3739801SMiguel Ojeda } 596*c3739801SMiguel Ojeda } 597*c3739801SMiguel Ojeda 598*c3739801SMiguel Ojeda impl<'a, T> Split<&'a mut T> 599*c3739801SMiguel Ojeda where 600*c3739801SMiguel Ojeda T: ?Sized + SplitAt, 601*c3739801SMiguel Ojeda { 602*c3739801SMiguel Ojeda #[inline(always)] 603*c3739801SMiguel Ojeda fn into_ptr(self) -> Split<Ptr<'a, T, (Exclusive, Aligned, Valid)>> { 604*c3739801SMiguel Ojeda let source = Ptr::from_mut(self.source); 605*c3739801SMiguel Ojeda // SAFETY: `Ptr::from_mut(self.source)` points to exactly `self.source`, 606*c3739801SMiguel Ojeda // and thus maintains the invariants of `self` with respect to `l_len`. 607*c3739801SMiguel Ojeda unsafe { Split::new(source, self.l_len) } 608*c3739801SMiguel Ojeda } 609*c3739801SMiguel Ojeda 610*c3739801SMiguel Ojeda /// Produces the split parts of `self`, using [`IntoBytes`] to ensure that 611*c3739801SMiguel Ojeda /// it is sound to have concurrent references to both parts. 612*c3739801SMiguel Ojeda /// 613*c3739801SMiguel Ojeda /// # Examples 614*c3739801SMiguel Ojeda /// 615*c3739801SMiguel Ojeda /// ``` 616*c3739801SMiguel Ojeda /// use zerocopy::{SplitAt, FromBytes}; 617*c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 618*c3739801SMiguel Ojeda /// 619*c3739801SMiguel Ojeda /// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes)] 620*c3739801SMiguel Ojeda /// #[repr(C)] 621*c3739801SMiguel Ojeda /// struct Packet<B: ?Sized> { 622*c3739801SMiguel Ojeda /// length: u8, 623*c3739801SMiguel Ojeda /// body: B, 624*c3739801SMiguel Ojeda /// } 625*c3739801SMiguel Ojeda /// 626*c3739801SMiguel Ojeda /// // These bytes encode a `Packet`. 627*c3739801SMiguel Ojeda /// let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 628*c3739801SMiguel Ojeda /// 629*c3739801SMiguel Ojeda /// let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap(); 630*c3739801SMiguel Ojeda /// 631*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 632*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); 633*c3739801SMiguel Ojeda /// 634*c3739801SMiguel Ojeda /// { 635*c3739801SMiguel Ojeda /// // Attempt to split `packet` at `length`. 636*c3739801SMiguel Ojeda /// let split = packet.split_at_mut(packet.length as usize).unwrap(); 637*c3739801SMiguel Ojeda /// 638*c3739801SMiguel Ojeda /// // Use the `IntoBytes` bound on `Packet` to prove that it's okay to 639*c3739801SMiguel Ojeda /// // return concurrent references to `packet` and `rest`. 640*c3739801SMiguel Ojeda /// let (packet, rest) = split.via_into_bytes(); 641*c3739801SMiguel Ojeda /// 642*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 643*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4]); 644*c3739801SMiguel Ojeda /// assert_eq!(rest, [5, 6, 7, 8, 9]); 645*c3739801SMiguel Ojeda /// 646*c3739801SMiguel Ojeda /// rest.fill(0); 647*c3739801SMiguel Ojeda /// } 648*c3739801SMiguel Ojeda /// 649*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 650*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]); 651*c3739801SMiguel Ojeda /// ``` 652*c3739801SMiguel Ojeda /// 653*c3739801SMiguel Ojeda /// # Code Generation 654*c3739801SMiguel Ojeda /// 655*c3739801SMiguel Ojeda /// See [`Split::via_immutable`](#method.split_via_immutable.codegen). 656*c3739801SMiguel Ojeda #[must_use = "has no side effects"] 657*c3739801SMiguel Ojeda #[inline(always)] 658*c3739801SMiguel Ojeda pub fn via_into_bytes(self) -> (&'a mut T, &'a mut [T::Elem]) 659*c3739801SMiguel Ojeda where 660*c3739801SMiguel Ojeda T: IntoBytes, 661*c3739801SMiguel Ojeda { 662*c3739801SMiguel Ojeda let (l, r) = self.into_ptr().via_into_bytes(); 663*c3739801SMiguel Ojeda (l.as_mut(), r.as_mut()) 664*c3739801SMiguel Ojeda } 665*c3739801SMiguel Ojeda 666*c3739801SMiguel Ojeda /// Produces the split parts of `self`, using [`Unaligned`] to ensure that 667*c3739801SMiguel Ojeda /// it is sound to have concurrent references to both parts. 668*c3739801SMiguel Ojeda /// 669*c3739801SMiguel Ojeda /// # Examples 670*c3739801SMiguel Ojeda /// 671*c3739801SMiguel Ojeda /// ``` 672*c3739801SMiguel Ojeda /// use zerocopy::{SplitAt, FromBytes}; 673*c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 674*c3739801SMiguel Ojeda /// 675*c3739801SMiguel Ojeda /// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes, Unaligned)] 676*c3739801SMiguel Ojeda /// #[repr(C)] 677*c3739801SMiguel Ojeda /// struct Packet<B: ?Sized> { 678*c3739801SMiguel Ojeda /// length: u8, 679*c3739801SMiguel Ojeda /// body: B, 680*c3739801SMiguel Ojeda /// } 681*c3739801SMiguel Ojeda /// 682*c3739801SMiguel Ojeda /// // These bytes encode a `Packet`. 683*c3739801SMiguel Ojeda /// let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 684*c3739801SMiguel Ojeda /// 685*c3739801SMiguel Ojeda /// let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap(); 686*c3739801SMiguel Ojeda /// 687*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 688*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); 689*c3739801SMiguel Ojeda /// 690*c3739801SMiguel Ojeda /// { 691*c3739801SMiguel Ojeda /// // Attempt to split `packet` at `length`. 692*c3739801SMiguel Ojeda /// let split = packet.split_at_mut(packet.length as usize).unwrap(); 693*c3739801SMiguel Ojeda /// 694*c3739801SMiguel Ojeda /// // Use the `Unaligned` bound on `Packet` to prove that it's okay to 695*c3739801SMiguel Ojeda /// // return concurrent references to `packet` and `rest`. 696*c3739801SMiguel Ojeda /// let (packet, rest) = split.via_unaligned(); 697*c3739801SMiguel Ojeda /// 698*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 699*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4]); 700*c3739801SMiguel Ojeda /// assert_eq!(rest, [5, 6, 7, 8, 9]); 701*c3739801SMiguel Ojeda /// 702*c3739801SMiguel Ojeda /// rest.fill(0); 703*c3739801SMiguel Ojeda /// } 704*c3739801SMiguel Ojeda /// 705*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 706*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]); 707*c3739801SMiguel Ojeda /// ``` 708*c3739801SMiguel Ojeda /// 709*c3739801SMiguel Ojeda /// # Code Generation 710*c3739801SMiguel Ojeda /// 711*c3739801SMiguel Ojeda /// See [`Split::via_immutable`](#method.split_via_immutable.codegen). 712*c3739801SMiguel Ojeda #[must_use = "has no side effects"] 713*c3739801SMiguel Ojeda #[inline(always)] 714*c3739801SMiguel Ojeda pub fn via_unaligned(self) -> (&'a mut T, &'a mut [T::Elem]) 715*c3739801SMiguel Ojeda where 716*c3739801SMiguel Ojeda T: Unaligned, 717*c3739801SMiguel Ojeda { 718*c3739801SMiguel Ojeda let (l, r) = self.into_ptr().via_unaligned(); 719*c3739801SMiguel Ojeda (l.as_mut(), r.as_mut()) 720*c3739801SMiguel Ojeda } 721*c3739801SMiguel Ojeda 722*c3739801SMiguel Ojeda /// Produces the split parts of `self`, using a dynamic check to ensure that 723*c3739801SMiguel Ojeda /// it is sound to have concurrent references to both parts. You should 724*c3739801SMiguel Ojeda /// prefer using [`Self::via_into_bytes`] or [`Self::via_unaligned`], which 725*c3739801SMiguel Ojeda /// have no runtime cost. 726*c3739801SMiguel Ojeda /// 727*c3739801SMiguel Ojeda /// # Examples 728*c3739801SMiguel Ojeda /// 729*c3739801SMiguel Ojeda /// ``` 730*c3739801SMiguel Ojeda /// use zerocopy::{SplitAt, FromBytes}; 731*c3739801SMiguel Ojeda /// # use zerocopy_derive::*; 732*c3739801SMiguel Ojeda /// 733*c3739801SMiguel Ojeda /// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes, Debug)] 734*c3739801SMiguel Ojeda /// #[repr(C)] 735*c3739801SMiguel Ojeda /// struct Packet<B: ?Sized> { 736*c3739801SMiguel Ojeda /// length: u8, 737*c3739801SMiguel Ojeda /// body: B, 738*c3739801SMiguel Ojeda /// } 739*c3739801SMiguel Ojeda /// 740*c3739801SMiguel Ojeda /// // These bytes encode a `Packet`. 741*c3739801SMiguel Ojeda /// let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..]; 742*c3739801SMiguel Ojeda /// 743*c3739801SMiguel Ojeda /// let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap(); 744*c3739801SMiguel Ojeda /// 745*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 746*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]); 747*c3739801SMiguel Ojeda /// 748*c3739801SMiguel Ojeda /// { 749*c3739801SMiguel Ojeda /// // Attempt to split `packet` at `length`. 750*c3739801SMiguel Ojeda /// let split = packet.split_at_mut(packet.length as usize).unwrap(); 751*c3739801SMiguel Ojeda /// 752*c3739801SMiguel Ojeda /// // Use a dynamic check to prove that it's okay to return concurrent 753*c3739801SMiguel Ojeda /// // references to `packet` and `rest`. 754*c3739801SMiguel Ojeda /// let (packet, rest) = split.via_runtime_check().unwrap(); 755*c3739801SMiguel Ojeda /// 756*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 757*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4]); 758*c3739801SMiguel Ojeda /// assert_eq!(rest, [5, 6, 7, 8, 9]); 759*c3739801SMiguel Ojeda /// 760*c3739801SMiguel Ojeda /// rest.fill(0); 761*c3739801SMiguel Ojeda /// } 762*c3739801SMiguel Ojeda /// 763*c3739801SMiguel Ojeda /// assert_eq!(packet.length, 4); 764*c3739801SMiguel Ojeda /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]); 765*c3739801SMiguel Ojeda /// ``` 766*c3739801SMiguel Ojeda /// 767*c3739801SMiguel Ojeda /// # Code Generation 768*c3739801SMiguel Ojeda /// 769*c3739801SMiguel Ojeda /// See [`Split::via_runtime_check`](#method.split_via_runtime_check.codegen). 770*c3739801SMiguel Ojeda #[must_use = "has no side effects"] 771*c3739801SMiguel Ojeda #[inline(always)] 772*c3739801SMiguel Ojeda pub fn via_runtime_check(self) -> Result<(&'a mut T, &'a mut [T::Elem]), Self> { 773*c3739801SMiguel Ojeda match self.into_ptr().via_runtime_check() { 774*c3739801SMiguel Ojeda Ok((l, r)) => Ok((l.as_mut(), r.as_mut())), 775*c3739801SMiguel Ojeda Err(s) => Err(s.into_mut()), 776*c3739801SMiguel Ojeda } 777*c3739801SMiguel Ojeda } 778*c3739801SMiguel Ojeda 779*c3739801SMiguel Ojeda /// Unsafely produces the split parts of `self`. 780*c3739801SMiguel Ojeda /// 781*c3739801SMiguel Ojeda /// # Safety 782*c3739801SMiguel Ojeda /// 783*c3739801SMiguel Ojeda /// The trailing padding bytes of the left portion must not overlap the 784*c3739801SMiguel Ojeda /// right portion. For some dynamically sized types, the padding that 785*c3739801SMiguel Ojeda /// appears after the trailing slice field [is a dynamic function of the 786*c3739801SMiguel Ojeda /// trailing slice length](KnownLayout#slice-dst-layout). Thus, for some 787*c3739801SMiguel Ojeda /// types, this condition is dependent on the length of the left portion. 788*c3739801SMiguel Ojeda /// 789*c3739801SMiguel Ojeda /// # Code Generation 790*c3739801SMiguel Ojeda /// 791*c3739801SMiguel Ojeda /// See [`Split::via_unchecked`](#method.split_via_unchecked.codegen). 792*c3739801SMiguel Ojeda #[must_use = "has no side effects"] 793*c3739801SMiguel Ojeda #[inline(always)] 794*c3739801SMiguel Ojeda pub unsafe fn via_unchecked(self) -> (&'a mut T, &'a mut [T::Elem]) { 795*c3739801SMiguel Ojeda // SAFETY: The aliasing of `self.into_ptr()` is `Exclusive`, and the 796*c3739801SMiguel Ojeda // caller has promised that the left and right portions of `self` split 797*c3739801SMiguel Ojeda // at `l_len` do not overlap. 798*c3739801SMiguel Ojeda let (l, r) = unsafe { self.into_ptr().via_unchecked() }; 799*c3739801SMiguel Ojeda (l.as_mut(), r.as_mut()) 800*c3739801SMiguel Ojeda } 801*c3739801SMiguel Ojeda } 802*c3739801SMiguel Ojeda 803*c3739801SMiguel Ojeda impl<'a, T, I> Split<Ptr<'a, T, I>> 804*c3739801SMiguel Ojeda where 805*c3739801SMiguel Ojeda T: ?Sized + SplitAt, 806*c3739801SMiguel Ojeda I: Invariants<Alignment = Aligned, Validity = Valid>, 807*c3739801SMiguel Ojeda { 808*c3739801SMiguel Ojeda fn into_ref(self) -> Split<&'a T> 809*c3739801SMiguel Ojeda where 810*c3739801SMiguel Ojeda I: Invariants<Aliasing = Shared>, 811*c3739801SMiguel Ojeda { 812*c3739801SMiguel Ojeda // SAFETY: `self.source.as_ref()` points to exactly the same referent as 813*c3739801SMiguel Ojeda // `self.source` and thus maintains the invariants of `self` with 814*c3739801SMiguel Ojeda // respect to `l_len`. 815*c3739801SMiguel Ojeda unsafe { Split::new(self.source.as_ref(), self.l_len) } 816*c3739801SMiguel Ojeda } 817*c3739801SMiguel Ojeda 818*c3739801SMiguel Ojeda fn into_mut(self) -> Split<&'a mut T> 819*c3739801SMiguel Ojeda where 820*c3739801SMiguel Ojeda I: Invariants<Aliasing = Exclusive>, 821*c3739801SMiguel Ojeda { 822*c3739801SMiguel Ojeda // SAFETY: `self.source.as_mut()` points to exactly the same referent as 823*c3739801SMiguel Ojeda // `self.source` and thus maintains the invariants of `self` with 824*c3739801SMiguel Ojeda // respect to `l_len`. 825*c3739801SMiguel Ojeda unsafe { Split::new(self.source.unify_invariants().as_mut(), self.l_len) } 826*c3739801SMiguel Ojeda } 827*c3739801SMiguel Ojeda 828*c3739801SMiguel Ojeda /// Produces the length of `self`'s left part. 829*c3739801SMiguel Ojeda #[inline(always)] 830*c3739801SMiguel Ojeda fn l_len(&self) -> MetadataOf<T> { 831*c3739801SMiguel Ojeda // SAFETY: By invariant on `Split`, `self.l_len` is not greater than the 832*c3739801SMiguel Ojeda // length of `self.source`. 833*c3739801SMiguel Ojeda unsafe { MetadataOf::<T>::new_unchecked(self.l_len) } 834*c3739801SMiguel Ojeda } 835*c3739801SMiguel Ojeda 836*c3739801SMiguel Ojeda /// Produces the split parts of `self`, using [`Immutable`] to ensure that 837*c3739801SMiguel Ojeda /// it is sound to have concurrent references to both parts. 838*c3739801SMiguel Ojeda #[inline(always)] 839*c3739801SMiguel Ojeda fn via_immutable(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) 840*c3739801SMiguel Ojeda where 841*c3739801SMiguel Ojeda T: Immutable, 842*c3739801SMiguel Ojeda I: Invariants<Aliasing = Shared>, 843*c3739801SMiguel Ojeda { 844*c3739801SMiguel Ojeda // SAFETY: `Aliasing = Shared` and `T: Immutable`. 845*c3739801SMiguel Ojeda unsafe { self.via_unchecked() } 846*c3739801SMiguel Ojeda } 847*c3739801SMiguel Ojeda 848*c3739801SMiguel Ojeda /// Produces the split parts of `self`, using [`IntoBytes`] to ensure that 849*c3739801SMiguel Ojeda /// it is sound to have concurrent references to both parts. 850*c3739801SMiguel Ojeda #[inline(always)] 851*c3739801SMiguel Ojeda fn via_into_bytes(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) 852*c3739801SMiguel Ojeda where 853*c3739801SMiguel Ojeda T: IntoBytes, 854*c3739801SMiguel Ojeda { 855*c3739801SMiguel Ojeda // SAFETY: By `T: IntoBytes`, `T` has no padding for any length. 856*c3739801SMiguel Ojeda // Consequently, `T` can be split into non-overlapping parts at any 857*c3739801SMiguel Ojeda // index. 858*c3739801SMiguel Ojeda unsafe { self.via_unchecked() } 859*c3739801SMiguel Ojeda } 860*c3739801SMiguel Ojeda 861*c3739801SMiguel Ojeda /// Produces the split parts of `self`, using [`Unaligned`] to ensure that 862*c3739801SMiguel Ojeda /// it is sound to have concurrent references to both parts. 863*c3739801SMiguel Ojeda #[inline(always)] 864*c3739801SMiguel Ojeda fn via_unaligned(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) 865*c3739801SMiguel Ojeda where 866*c3739801SMiguel Ojeda T: Unaligned, 867*c3739801SMiguel Ojeda { 868*c3739801SMiguel Ojeda // SAFETY: By `T: SplitAt + Unaligned`, `T` is either a slice or a 869*c3739801SMiguel Ojeda // `repr(C)` or `repr(transparent)` slice DST that is well-aligned at 870*c3739801SMiguel Ojeda // any address and length. If `T` is a slice DST with alignment 1, 871*c3739801SMiguel Ojeda // `repr(C)` or `repr(transparent)` ensures that no padding is placed 872*c3739801SMiguel Ojeda // after the final element of the trailing slice. Consequently, `T` can 873*c3739801SMiguel Ojeda // be split into strictly non-overlapping parts any any index. 874*c3739801SMiguel Ojeda unsafe { self.via_unchecked() } 875*c3739801SMiguel Ojeda } 876*c3739801SMiguel Ojeda 877*c3739801SMiguel Ojeda /// Produces the split parts of `self`, using a dynamic check to ensure that 878*c3739801SMiguel Ojeda /// it is sound to have concurrent references to both parts. You should 879*c3739801SMiguel Ojeda /// prefer using [`Self::via_immutable`], [`Self::via_into_bytes`], or 880*c3739801SMiguel Ojeda /// [`Self::via_unaligned`], which have no runtime cost. 881*c3739801SMiguel Ojeda #[inline(always)] 882*c3739801SMiguel Ojeda fn via_runtime_check(self) -> Result<(Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>), Self> { 883*c3739801SMiguel Ojeda let l_len = self.l_len(); 884*c3739801SMiguel Ojeda // FIXME(#1290): Once we require `KnownLayout` on all fields, add an 885*c3739801SMiguel Ojeda // `IS_IMMUTABLE` associated const, and add `T::IS_IMMUTABLE ||` to the 886*c3739801SMiguel Ojeda // below check. 887*c3739801SMiguel Ojeda if l_len.padding_needed_for() == 0 { 888*c3739801SMiguel Ojeda // SAFETY: By `T: SplitAt`, `T` is either `[T]`, or a `repr(C)` or 889*c3739801SMiguel Ojeda // `repr(transparent)` slice DST, for which the trailing padding 890*c3739801SMiguel Ojeda // needed to accommodate `l_len` trailing elements is 891*c3739801SMiguel Ojeda // `l_len.padding_needed_for()`. If no trailing padding is required, 892*c3739801SMiguel Ojeda // the left and right parts are strictly non-overlapping. 893*c3739801SMiguel Ojeda Ok(unsafe { self.via_unchecked() }) 894*c3739801SMiguel Ojeda } else { 895*c3739801SMiguel Ojeda Err(self) 896*c3739801SMiguel Ojeda } 897*c3739801SMiguel Ojeda } 898*c3739801SMiguel Ojeda 899*c3739801SMiguel Ojeda /// Unsafely produces the split parts of `self`. 900*c3739801SMiguel Ojeda /// 901*c3739801SMiguel Ojeda /// # Safety 902*c3739801SMiguel Ojeda /// 903*c3739801SMiguel Ojeda /// The caller promises that if `I::Aliasing` is [`Exclusive`] or `T` 904*c3739801SMiguel Ojeda /// permits interior mutation, then `l_len.padding_needed_for() == 0`. 905*c3739801SMiguel Ojeda #[inline(always)] 906*c3739801SMiguel Ojeda unsafe fn via_unchecked(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) { 907*c3739801SMiguel Ojeda let l_len = self.l_len(); 908*c3739801SMiguel Ojeda let inner = self.source.as_inner(); 909*c3739801SMiguel Ojeda 910*c3739801SMiguel Ojeda // SAFETY: By invariant on `Self::l_len`, `l_len` is not greater than 911*c3739801SMiguel Ojeda // the length of `inner`'s trailing slice. 912*c3739801SMiguel Ojeda let (left, right) = unsafe { inner.split_at_unchecked(l_len) }; 913*c3739801SMiguel Ojeda 914*c3739801SMiguel Ojeda // Lemma 0: `left` and `right` conform to the aliasing invariant 915*c3739801SMiguel Ojeda // `I::Aliasing`. Proof: If `I::Aliasing` is `Exclusive` or `T` permits 916*c3739801SMiguel Ojeda // interior mutation, the caller promises that `l_len.padding_needed_for() 917*c3739801SMiguel Ojeda // == 0`. Consequently, by post-condition on `PtrInner::split_at_unchecked`, 918*c3739801SMiguel Ojeda // there is no trailing padding after `left`'s final element that would 919*c3739801SMiguel Ojeda // overlap into `right`. If `I::Aliasing` is shared and `T` forbids interior 920*c3739801SMiguel Ojeda // mutation, then overlap between their referents is permissible. 921*c3739801SMiguel Ojeda 922*c3739801SMiguel Ojeda // SAFETY: 923*c3739801SMiguel Ojeda // 0. `left` conforms to the aliasing invariant of `I::Aliasing`, by Lemma 0. 924*c3739801SMiguel Ojeda // 1. `left` conforms to the alignment invariant of `I::Alignment, because 925*c3739801SMiguel Ojeda // the referents of `left` and `Self` have the same address and type 926*c3739801SMiguel Ojeda // (and, thus, alignment requirement). 927*c3739801SMiguel Ojeda // 2. `left` conforms to the validity invariant of `I::Validity`, neither 928*c3739801SMiguel Ojeda // the type nor bytes of `left`'s referent have been changed. 929*c3739801SMiguel Ojeda let left = unsafe { Ptr::from_inner(left) }; 930*c3739801SMiguel Ojeda 931*c3739801SMiguel Ojeda // SAFETY: 932*c3739801SMiguel Ojeda // 0. `right` conforms to the aliasing invariant of `I::Aliasing`, by Lemma 933*c3739801SMiguel Ojeda // 0. 934*c3739801SMiguel Ojeda // 1. `right` conforms to the alignment invariant of `I::Alignment, because 935*c3739801SMiguel Ojeda // if `ptr` with `I::Alignment = Aligned`, then by invariant on `T: 936*c3739801SMiguel Ojeda // SplitAt`, the trailing slice of `ptr` (from which `right` is derived) 937*c3739801SMiguel Ojeda // will also be well-aligned. 938*c3739801SMiguel Ojeda // 2. `right` conforms to the validity invariant of `I::Validity`, 939*c3739801SMiguel Ojeda // because `right: [T::Elem]` is derived from the trailing slice of 940*c3739801SMiguel Ojeda // `ptr`, which, by contract on `T: SplitAt::Elem`, has type 941*c3739801SMiguel Ojeda // `[T::Elem]`. The `left` part cannot be used to invalidate `right`, 942*c3739801SMiguel Ojeda // because the caller promises that if `I::Aliasing` is `Exclusive` 943*c3739801SMiguel Ojeda // or `T` permits interior mutation, then `l_len.padding_needed_for() 944*c3739801SMiguel Ojeda // == 0` and thus the parts will be non-overlapping. 945*c3739801SMiguel Ojeda let right = unsafe { Ptr::from_inner(right) }; 946*c3739801SMiguel Ojeda 947*c3739801SMiguel Ojeda (left, right) 948*c3739801SMiguel Ojeda } 949*c3739801SMiguel Ojeda } 950*c3739801SMiguel Ojeda 951*c3739801SMiguel Ojeda #[cfg(test)] 952*c3739801SMiguel Ojeda mod tests { 953*c3739801SMiguel Ojeda #[cfg(feature = "derive")] 954*c3739801SMiguel Ojeda #[test] 955*c3739801SMiguel Ojeda fn test_split_at() { 956*c3739801SMiguel Ojeda use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt}; 957*c3739801SMiguel Ojeda 958*c3739801SMiguel Ojeda #[derive(FromBytes, KnownLayout, SplitAt, IntoBytes, Immutable, Debug)] 959*c3739801SMiguel Ojeda #[repr(C)] 960*c3739801SMiguel Ojeda struct SliceDst<const OFFSET: usize> { 961*c3739801SMiguel Ojeda prefix: [u8; OFFSET], 962*c3739801SMiguel Ojeda trailing: [u8], 963*c3739801SMiguel Ojeda } 964*c3739801SMiguel Ojeda 965*c3739801SMiguel Ojeda #[allow(clippy::as_conversions)] 966*c3739801SMiguel Ojeda fn test_split_at<const OFFSET: usize, const BUFFER_SIZE: usize>() { 967*c3739801SMiguel Ojeda // Test `split_at` 968*c3739801SMiguel Ojeda let n: usize = BUFFER_SIZE - OFFSET; 969*c3739801SMiguel Ojeda let arr = [1; BUFFER_SIZE]; 970*c3739801SMiguel Ojeda let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap(); 971*c3739801SMiguel Ojeda for i in 0..=n { 972*c3739801SMiguel Ojeda let (l, r) = dst.split_at(i).unwrap().via_runtime_check().unwrap(); 973*c3739801SMiguel Ojeda let l_sum: u8 = l.trailing.iter().sum(); 974*c3739801SMiguel Ojeda let r_sum: u8 = r.iter().sum(); 975*c3739801SMiguel Ojeda assert_eq!(l_sum, i as u8); 976*c3739801SMiguel Ojeda assert_eq!(r_sum, (n - i) as u8); 977*c3739801SMiguel Ojeda assert_eq!(l_sum + r_sum, n as u8); 978*c3739801SMiguel Ojeda } 979*c3739801SMiguel Ojeda 980*c3739801SMiguel Ojeda // Test `split_at_mut` 981*c3739801SMiguel Ojeda let n: usize = BUFFER_SIZE - OFFSET; 982*c3739801SMiguel Ojeda let mut arr = [1; BUFFER_SIZE]; 983*c3739801SMiguel Ojeda let dst = SliceDst::<OFFSET>::mut_from_bytes(&mut arr[..]).unwrap(); 984*c3739801SMiguel Ojeda for i in 0..=n { 985*c3739801SMiguel Ojeda let (l, r) = dst.split_at_mut(i).unwrap().via_runtime_check().unwrap(); 986*c3739801SMiguel Ojeda let l_sum: u8 = l.trailing.iter().sum(); 987*c3739801SMiguel Ojeda let r_sum: u8 = r.iter().sum(); 988*c3739801SMiguel Ojeda assert_eq!(l_sum, i as u8); 989*c3739801SMiguel Ojeda assert_eq!(r_sum, (n - i) as u8); 990*c3739801SMiguel Ojeda assert_eq!(l_sum + r_sum, n as u8); 991*c3739801SMiguel Ojeda } 992*c3739801SMiguel Ojeda } 993*c3739801SMiguel Ojeda 994*c3739801SMiguel Ojeda test_split_at::<0, 16>(); 995*c3739801SMiguel Ojeda test_split_at::<1, 17>(); 996*c3739801SMiguel Ojeda test_split_at::<2, 18>(); 997*c3739801SMiguel Ojeda } 998*c3739801SMiguel Ojeda 999*c3739801SMiguel Ojeda #[cfg(feature = "derive")] 1000*c3739801SMiguel Ojeda #[test] 1001*c3739801SMiguel Ojeda #[allow(clippy::as_conversions)] 1002*c3739801SMiguel Ojeda fn test_split_at_overlapping() { 1003*c3739801SMiguel Ojeda use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt}; 1004*c3739801SMiguel Ojeda 1005*c3739801SMiguel Ojeda #[derive(FromBytes, KnownLayout, SplitAt, Immutable)] 1006*c3739801SMiguel Ojeda #[repr(C, align(2))] 1007*c3739801SMiguel Ojeda struct SliceDst { 1008*c3739801SMiguel Ojeda prefix: u8, 1009*c3739801SMiguel Ojeda trailing: [u8], 1010*c3739801SMiguel Ojeda } 1011*c3739801SMiguel Ojeda 1012*c3739801SMiguel Ojeda const N: usize = 16; 1013*c3739801SMiguel Ojeda 1014*c3739801SMiguel Ojeda let arr = [1u16; N]; 1015*c3739801SMiguel Ojeda let dst = SliceDst::ref_from_bytes(arr.as_bytes()).unwrap(); 1016*c3739801SMiguel Ojeda 1017*c3739801SMiguel Ojeda for i in 0..N { 1018*c3739801SMiguel Ojeda let split = dst.split_at(i).unwrap().via_runtime_check(); 1019*c3739801SMiguel Ojeda if i % 2 == 1 { 1020*c3739801SMiguel Ojeda assert!(split.is_ok()); 1021*c3739801SMiguel Ojeda } else { 1022*c3739801SMiguel Ojeda assert!(split.is_err()); 1023*c3739801SMiguel Ojeda } 1024*c3739801SMiguel Ojeda } 1025*c3739801SMiguel Ojeda } 1026*c3739801SMiguel Ojeda #[test] 1027*c3739801SMiguel Ojeda fn test_split_at_unchecked() { 1028*c3739801SMiguel Ojeda use crate::SplitAt; 1029*c3739801SMiguel Ojeda let mut arr = [1, 2, 3, 4]; 1030*c3739801SMiguel Ojeda let slice = &arr[..]; 1031*c3739801SMiguel Ojeda // SAFETY: 2 <= arr.len() (4) 1032*c3739801SMiguel Ojeda let split = unsafe { SplitAt::split_at_unchecked(slice, 2) }; 1033*c3739801SMiguel Ojeda // SAFETY: SplitAt::split_at_unchecked guarantees that the split is valid. 1034*c3739801SMiguel Ojeda let (l, r) = unsafe { split.via_unchecked() }; 1035*c3739801SMiguel Ojeda assert_eq!(l, &[1, 2]); 1036*c3739801SMiguel Ojeda assert_eq!(r, &[3, 4]); 1037*c3739801SMiguel Ojeda 1038*c3739801SMiguel Ojeda let slice_mut = &mut arr[..]; 1039*c3739801SMiguel Ojeda // SAFETY: 2 <= arr.len() (4) 1040*c3739801SMiguel Ojeda let split = unsafe { SplitAt::split_at_mut_unchecked(slice_mut, 2) }; 1041*c3739801SMiguel Ojeda // SAFETY: SplitAt::split_at_mut_unchecked guarantees that the split is valid. 1042*c3739801SMiguel Ojeda let (l, r) = unsafe { split.via_unchecked() }; 1043*c3739801SMiguel Ojeda assert_eq!(l, &mut [1, 2]); 1044*c3739801SMiguel Ojeda assert_eq!(r, &mut [3, 4]); 1045*c3739801SMiguel Ojeda } 1046*c3739801SMiguel Ojeda 1047*c3739801SMiguel Ojeda #[test] 1048*c3739801SMiguel Ojeda fn test_split_at_via_methods() { 1049*c3739801SMiguel Ojeda use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt}; 1050*c3739801SMiguel Ojeda #[derive(FromBytes, KnownLayout, SplitAt, IntoBytes, Immutable, Debug)] 1051*c3739801SMiguel Ojeda #[repr(C)] 1052*c3739801SMiguel Ojeda struct Packet { 1053*c3739801SMiguel Ojeda length: u8, 1054*c3739801SMiguel Ojeda body: [u8], 1055*c3739801SMiguel Ojeda } 1056*c3739801SMiguel Ojeda 1057*c3739801SMiguel Ojeda let arr = [1, 2, 3, 4]; 1058*c3739801SMiguel Ojeda let packet = Packet::ref_from_bytes(&arr[..]).unwrap(); 1059*c3739801SMiguel Ojeda 1060*c3739801SMiguel Ojeda let split1 = packet.split_at(2).unwrap(); 1061*c3739801SMiguel Ojeda let (l, r) = split1.via_immutable(); 1062*c3739801SMiguel Ojeda assert_eq!(l.length, 1); 1063*c3739801SMiguel Ojeda assert_eq!(r, &[4]); 1064*c3739801SMiguel Ojeda 1065*c3739801SMiguel Ojeda let split2 = packet.split_at(2).unwrap(); 1066*c3739801SMiguel Ojeda let (l, r) = split2.via_into_bytes(); 1067*c3739801SMiguel Ojeda assert_eq!(l.length, 1); 1068*c3739801SMiguel Ojeda assert_eq!(r, &[4]); 1069*c3739801SMiguel Ojeda } 1070*c3739801SMiguel Ojeda #[test] 1071*c3739801SMiguel Ojeda fn test_split_at_via_unaligned() { 1072*c3739801SMiguel Ojeda use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt, Unaligned}; 1073*c3739801SMiguel Ojeda #[derive(FromBytes, KnownLayout, SplitAt, IntoBytes, Immutable, Unaligned)] 1074*c3739801SMiguel Ojeda #[repr(C)] 1075*c3739801SMiguel Ojeda struct Packet { 1076*c3739801SMiguel Ojeda length: u8, 1077*c3739801SMiguel Ojeda body: [u8], 1078*c3739801SMiguel Ojeda } 1079*c3739801SMiguel Ojeda 1080*c3739801SMiguel Ojeda let arr = [1, 2, 3, 4]; 1081*c3739801SMiguel Ojeda let packet = Packet::ref_from_bytes(&arr[..]).unwrap(); 1082*c3739801SMiguel Ojeda 1083*c3739801SMiguel Ojeda let split = packet.split_at(2).unwrap(); 1084*c3739801SMiguel Ojeda let (l, r) = split.via_unaligned(); 1085*c3739801SMiguel Ojeda assert_eq!(l.length, 1); 1086*c3739801SMiguel Ojeda assert_eq!(r, &[4]); 1087*c3739801SMiguel Ojeda } 1088*c3739801SMiguel Ojeda } 1089