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