xref: /linux/rust/zerocopy/src/split_at.rs (revision c37398010a05055e78cf0c75defb90df06c4e999)
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