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