Skip to main content

zerocopy/
split_at.rs

1// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT
2//
3// Copyright 2025 The Fuchsia Authors
4//
5// Licensed under the 2-Clause BSD License <LICENSE-BSD or
6// https://opensource.org/license/bsd-2-clause>, Apache License, Version 2.0
7// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
8// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
9// This file may not be copied, modified, or distributed except according to
10// those terms.
11
12use super::*;
13use crate::pointer::invariant::{Aligned, Exclusive, Invariants, Safe, Shared};
14
15/// Types that can be split in two.
16///
17/// This trait generalizes Rust's existing support for splitting slices to
18/// support slices and slice-based dynamically-sized types ("slice DSTs").
19///
20/// For a `repr(C, packed)` or `repr(C, packed(N))` struct, the derive wraps
21/// the trailing field's [`Elem`](Self::Elem) in [`Unalign`]. The returned
22/// slice can therefore be accessed even when packing misaligns the original
23/// elements. Each packed struct in the trailing-field chain adds one wrapper;
24/// unpacked structs and [`ManuallyDrop`] forward their trailing type's `Elem`.
25///
26/// # Implementation
27///
28/// **Do not implement this trait yourself!** Instead, use
29/// [`#[derive(SplitAt)]`][derive]; e.g.:
30///
31/// ```
32/// # use zerocopy_derive::{SplitAt, KnownLayout};
33/// #[derive(SplitAt, KnownLayout)]
34/// #[repr(C)]
35/// struct MyStruct<T: ?Sized> {
36/// # /*
37///     ...,
38/// # */
39///     // `SplitAt` types must have at least one field.
40///     field: T,
41/// }
42/// ```
43///
44/// This derive performs a sophisticated, compile-time safety analysis to
45/// determine whether a type is `SplitAt`.
46///
47/// A packed struct exposes its trailing elements through `Unalign`:
48///
49/// ```
50/// use zerocopy::{FromBytes, SplitAt, Unalign};
51/// # use zerocopy_derive::*;
52///
53/// #[derive(FromBytes, IntoBytes, KnownLayout, SplitAt)]
54/// #[repr(C, packed)]
55/// struct Packet {
56///     tag: u8,
57///     words: [u16],
58/// }
59///
60/// let mut bytes = [0u8; 5];
61/// let packet = Packet::mut_from_bytes(&mut bytes[..]).unwrap();
62/// let (left, right): (&mut Packet, &mut [Unalign<u16>]) =
63///     packet.split_at_mut(1).unwrap().via_into_bytes();
64/// left.tag = 1;
65/// right[0] = Unalign::new(0x0202);
66/// assert_eq!(bytes, [1, 0, 0, 2, 2]);
67/// ```
68///
69/// # Safety
70///
71/// This trait does not convey any safety guarantees to code outside this crate.
72///
73/// You must not rely on the `#[doc(hidden)]` internals of `SplitAt`. Future
74/// releases of zerocopy may make backwards-breaking changes to these items,
75/// including changes that only affect soundness, which may cause code which
76/// uses those items to silently become unsound.
77///
78#[cfg_attr(feature = "derive", doc = "[derive]: zerocopy_derive::SplitAt")]
79#[cfg_attr(
80    not(feature = "derive"),
81    doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.SplitAt.html"),
82)]
83#[cfg_attr(
84    not(no_zerocopy_diagnostic_on_unimplemented_1_78_0),
85    diagnostic::on_unimplemented(note = "Consider adding `#[derive(SplitAt)]` to `{Self}`")
86)]
87// # Safety
88//
89// `Self` is a slice, a `repr(C)` (possibly packed) or `repr(transparent)` slice
90// DST, or `ManuallyDrop<T>` for some `T: SplitAt`.
91//
92// `Self::Elem` has the same size, bit validity, and `UnsafeCell` coverage as
93// the actual trailing element type. Access through either representation
94// preserves the other's validity, including writes through mutable references
95// and interior mutation through shared references. For every aligned `Self`,
96// its trailing slice's address is aligned for `Self::Elem`.
97pub unsafe trait SplitAt: KnownLayout<PointerMetadata = usize> {
98    /// The element type exposed by the split's returned slice.
99    ///
100    /// For `[T]`, this is `T`. For a struct, this is the trailing field's `Elem`,
101    /// wrapped in [`Unalign`] if the struct is packed. Nested packed structs
102    /// produce nested `Unalign` wrappers.
103    type Elem;
104
105    #[doc(hidden)]
106    fn only_derive_is_allowed_to_implement_this_trait()
107    where
108        Self: Sized;
109
110    /// Unsafely splits `self` in two.
111    ///
112    /// # Safety
113    ///
114    /// The caller promises that `l_len` is not greater than the length of
115    /// `self`'s trailing slice.
116    ///
117    #[doc = codegen_section!(
118        header = "h5",
119        bench = "split_at_unchecked",
120        format = "coco",
121        arity = 2,
122        [
123            open
124            @index 1
125            @title "Unsized"
126            @variant "dynamic_size"
127        ],
128        [
129            @index 2
130            @title "Dynamically Padded"
131            @variant "dynamic_padding"
132        ]
133    )]
134    #[inline]
135    #[must_use]
136    unsafe fn split_at_unchecked(&self, l_len: usize) -> Split<&Self> {
137        // SAFETY: By precondition on the caller, `l_len <= self.len()`.
138        unsafe { Split::<&Self>::new(self, l_len) }
139    }
140
141    /// Attempts to split `self` in two.
142    ///
143    /// Returns `None` if `l_len` is greater than the length of `self`'s
144    /// trailing slice.
145    ///
146    /// # Examples
147    ///
148    /// ```
149    /// use zerocopy::{SplitAt, FromBytes};
150    /// # use zerocopy_derive::*;
151    ///
152    /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable)]
153    /// #[repr(C)]
154    /// struct Packet {
155    ///     length: u8,
156    ///     body: [u8],
157    /// }
158    ///
159    /// // These bytes encode a `Packet`.
160    /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
161    ///
162    /// let packet = Packet::ref_from_bytes(bytes).unwrap();
163    ///
164    /// assert_eq!(packet.length, 4);
165    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
166    ///
167    /// // Attempt to split `packet` at `length`.
168    /// let split = packet.split_at(packet.length as usize).unwrap();
169    ///
170    /// // Use the `Immutable` bound on `Packet` to prove that it's okay to
171    /// // return concurrent references to `packet` and `rest`.
172    /// let (packet, rest) = split.via_immutable();
173    ///
174    /// assert_eq!(packet.length, 4);
175    /// assert_eq!(packet.body, [1, 2, 3, 4]);
176    /// assert_eq!(rest, [5, 6, 7, 8, 9]);
177    /// ```
178    ///
179    #[doc = codegen_section!(
180        header = "h5",
181        bench = "split_at",
182        format = "coco",
183        arity = 2,
184        [
185            open
186            @index 1
187            @title "Unsized"
188            @variant "dynamic_size"
189        ],
190        [
191            @index 2
192            @title "Dynamically Padded"
193            @variant "dynamic_padding"
194        ]
195    )]
196    #[inline]
197    #[must_use = "has no side effects"]
198    fn split_at(&self, l_len: usize) -> Option<Split<&Self>> {
199        MetadataOf::new_in_bounds(self, l_len).map(
200            #[inline(always)]
201            |l_len| {
202                // SAFETY: We have ensured that `l_len <= self.len()` (by
203                // post-condition on `MetadataOf::new_in_bounds`)
204                unsafe { Split::new(self, l_len.get()) }
205            },
206        )
207    }
208
209    /// Unsafely splits `self` in two.
210    ///
211    /// # Safety
212    ///
213    /// The caller promises that `l_len` is not greater than the length of
214    /// `self`'s trailing slice.
215    ///
216    #[doc = codegen_header!("h5", "split_at_mut_unchecked")]
217    ///
218    /// See [`SplitAt::split_at_unchecked`](#method.split_at_unchecked.codegen).
219    #[inline]
220    #[must_use]
221    unsafe fn split_at_mut_unchecked(&mut self, l_len: usize) -> Split<&mut Self> {
222        // SAFETY: By precondition on the caller, `l_len <= self.len()`.
223        unsafe { Split::<&mut Self>::new(self, l_len) }
224    }
225
226    /// Attempts to split `self` in two.
227    ///
228    /// Returns `None` if `l_len` is greater than the length of `self`'s
229    /// trailing slice.
230    ///
231    /// # Examples
232    ///
233    /// ```
234    /// use zerocopy::{SplitAt, FromBytes};
235    /// # use zerocopy_derive::*;
236    ///
237    /// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes)]
238    /// #[repr(C)]
239    /// struct Packet<B: ?Sized> {
240    ///     length: u8,
241    ///     body: B,
242    /// }
243    ///
244    /// // These bytes encode a `Packet`.
245    /// let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
246    ///
247    /// let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap();
248    ///
249    /// assert_eq!(packet.length, 4);
250    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
251    ///
252    /// {
253    ///     // Attempt to split `packet` at `length`.
254    ///     let split = packet.split_at_mut(packet.length as usize).unwrap();
255    ///
256    ///     // Use the `IntoBytes` bound on `Packet` to prove that it's okay to
257    ///     // return concurrent references to `packet` and `rest`.
258    ///     let (packet, rest) = split.via_into_bytes();
259    ///
260    ///     assert_eq!(packet.length, 4);
261    ///     assert_eq!(packet.body, [1, 2, 3, 4]);
262    ///     assert_eq!(rest, [5, 6, 7, 8, 9]);
263    ///
264    ///     rest.fill(0);
265    /// }
266    ///
267    /// assert_eq!(packet.length, 4);
268    /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]);
269    /// ```
270    ///
271    #[doc = codegen_header!("h5", "split_at_mut")]
272    ///
273    /// See [`SplitAt::split_at`](#method.split_at.codegen).
274    #[inline]
275    fn split_at_mut(&mut self, l_len: usize) -> Option<Split<&mut Self>> {
276        MetadataOf::new_in_bounds(self, l_len).map(
277            #[inline(always)]
278            |l_len| {
279                // SAFETY: We have ensured that `l_len <= self.len()` (by
280                // post-condition on `MetadataOf::new_in_bounds`)
281                unsafe { Split::new(self, l_len.get()) }
282            },
283        )
284    }
285}
286
287// SAFETY: `[T]` exposes its own element type, preserving size, validity, and
288// `UnsafeCell` coverage. An aligned slice is aligned for its elements.
289unsafe impl<T> SplitAt for [T] {
290    type Elem = T;
291
292    #[inline]
293    #[allow(dead_code)]
294    fn only_derive_is_allowed_to_implement_this_trait()
295    where
296        Self: Sized,
297    {
298    }
299}
300
301// SAFETY: `ManuallyDrop<T>` has the same layout and bit validity as `T` [1].
302// Its `KnownLayout` implementation preserves `T`'s metadata and trailing-slice
303// layout. Forwarding `T::Elem` therefore preserves its size, validity, and
304// alignment guarantees. Its `UnsafeCell` coverage also matches `T`'s, as
305// established for `ManuallyDrop` in `impls.rs`; accesses through the forwarded
306// element representation preserve validity in both directions.
307//
308// [1] Per https://doc.rust-lang.org/1.93.0/std/mem/struct.ManuallyDrop.html:
309//
310//   `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as
311//   `T`
312unsafe impl<T: ?Sized + SplitAt> SplitAt for ManuallyDrop<T> {
313    type Elem = T::Elem;
314
315    #[inline]
316    #[allow(dead_code)]
317    fn only_derive_is_allowed_to_implement_this_trait()
318    where
319        Self: Sized,
320    {
321    }
322}
323
324/// A `T` that has been split into two possibly-overlapping parts.
325///
326/// For some dynamically sized types, the padding that appears after the
327/// trailing slice field [is a dynamic function of the trailing slice
328/// length](KnownLayout#slice-dst-layout). If `T` is split at a length that
329/// requires trailing padding, the trailing padding of the left part of the
330/// split `T` will overlap the right part. If `T` is a mutable reference or
331/// permits interior mutation, you must ensure that the left and right parts do
332/// not overlap. Use [`Self::via_into_bytes`] or
333/// [`Self::via_no_dynamic_padding`] to establish this without a runtime check,
334/// or [`Self::via_runtime_check`] to check a particular split. Shared references
335/// to an [`Immutable`] type may overlap; use [`Self::via_immutable`] in that
336/// case.
337#[derive(Debug)]
338pub struct Split<T> {
339    /// A pointer to the source slice DST.
340    source: T,
341    /// The length of the future left half of `source`.
342    ///
343    /// # Safety
344    ///
345    /// If `source` is a pointer to a slice DST, `l_len` is no greater than
346    /// `source`'s length.
347    l_len: usize,
348}
349
350impl<T> Split<T> {
351    /// Produces a `Split` of `source` with `l_len`.
352    ///
353    /// # Safety
354    ///
355    /// `l_len` is no greater than `source`'s length.
356    #[inline(always)]
357    unsafe fn new(source: T, l_len: usize) -> Self {
358        Self { source, l_len }
359    }
360}
361
362impl<'a, T> Split<&'a T>
363where
364    T: ?Sized + SplitAt,
365{
366    #[inline(always)]
367    fn into_ptr(self) -> Split<Ptr<'a, T, (Shared, Aligned, Safe)>> {
368        let source = Ptr::from_ref(self.source);
369        // SAFETY: `Ptr::from_ref(self.source)` points to exactly `self.source`
370        // and thus maintains the invariants of `self` with respect to `l_len`.
371        unsafe { Split::new(source, self.l_len) }
372    }
373
374    /// Produces the split parts of `self`, using [`Immutable`] to ensure that
375    /// it is sound to have concurrent references to both parts.
376    ///
377    /// # Examples
378    ///
379    /// ```
380    /// use zerocopy::{SplitAt, FromBytes};
381    /// # use zerocopy_derive::*;
382    ///
383    /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable)]
384    /// #[repr(C)]
385    /// struct Packet {
386    ///     length: u8,
387    ///     body: [u8],
388    /// }
389    ///
390    /// // These bytes encode a `Packet`.
391    /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
392    ///
393    /// let packet = Packet::ref_from_bytes(bytes).unwrap();
394    ///
395    /// assert_eq!(packet.length, 4);
396    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
397    ///
398    /// // Attempt to split `packet` at `length`.
399    /// let split = packet.split_at(packet.length as usize).unwrap();
400    ///
401    /// // Use the `Immutable` bound on `Packet` to prove that it's okay to
402    /// // return concurrent references to `packet` and `rest`.
403    /// let (packet, rest) = split.via_immutable();
404    ///
405    /// assert_eq!(packet.length, 4);
406    /// assert_eq!(packet.body, [1, 2, 3, 4]);
407    /// assert_eq!(rest, [5, 6, 7, 8, 9]);
408    /// ```
409    ///
410    #[doc = codegen_section!(
411        header = "h5",
412        bench = "split_via_immutable",
413        format = "coco",
414        arity = 2,
415        [
416            open
417            @index 1
418            @title "Unsized"
419            @variant "dynamic_size"
420        ],
421        [
422            @index 2
423            @title "Dynamically Padded"
424            @variant "dynamic_padding"
425        ]
426    )]
427    #[must_use = "has no side effects"]
428    #[inline(always)]
429    pub fn via_immutable(self) -> (&'a T, &'a [T::Elem])
430    where
431        T: Immutable,
432    {
433        let (l, r) = self.into_ptr().via_immutable();
434        (l.as_ref(), r.as_ref())
435    }
436
437    /// Produces the split parts of `self`, using [`IntoBytes`] to ensure that
438    /// it is sound to have concurrent references to both parts.
439    ///
440    /// # Examples
441    ///
442    /// ```
443    /// use zerocopy::{SplitAt, FromBytes};
444    /// # use zerocopy_derive::*;
445    ///
446    /// #[derive(SplitAt, FromBytes, KnownLayout, Immutable, IntoBytes)]
447    /// #[repr(C)]
448    /// struct Packet<B: ?Sized> {
449    ///     length: u8,
450    ///     body: B,
451    /// }
452    ///
453    /// // These bytes encode a `Packet`.
454    /// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
455    ///
456    /// let packet = Packet::<[u8]>::ref_from_bytes(bytes).unwrap();
457    ///
458    /// assert_eq!(packet.length, 4);
459    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
460    ///
461    /// // Attempt to split `packet` at `length`.
462    /// let split = packet.split_at(packet.length as usize).unwrap();
463    ///
464    /// // Use the `IntoBytes` bound on `Packet` to prove that it's okay to
465    /// // return concurrent references to `packet` and `rest`.
466    /// let (packet, rest) = split.via_into_bytes();
467    ///
468    /// assert_eq!(packet.length, 4);
469    /// assert_eq!(packet.body, [1, 2, 3, 4]);
470    /// assert_eq!(rest, [5, 6, 7, 8, 9]);
471    /// ```
472    ///
473    #[doc = codegen_header!("h5", "split_via_into_bytes")]
474    ///
475    /// See [`Split::via_immutable`](#method.split_via_immutable.codegen).
476    #[must_use = "has no side effects"]
477    #[inline(always)]
478    pub fn via_into_bytes(self) -> (&'a T, &'a [T::Elem])
479    where
480        T: IntoBytes,
481    {
482        let (l, r) = self.into_ptr().via_into_bytes();
483        (l.as_ref(), r.as_ref())
484    }
485
486    /// Produces the split parts of `self` using [`Self::via_no_dynamic_padding`].
487    #[deprecated(note = "use `Split::via_no_dynamic_padding` instead")]
488    #[doc(hidden)]
489    #[must_use = "has no side effects"]
490    #[inline(always)]
491    pub fn via_unaligned(self) -> (&'a T, &'a [T::Elem])
492    where
493        T: Unaligned,
494    {
495        self.via_no_dynamic_padding()
496    }
497
498    /// Produces the split parts of `self` using a compile-time assertion to
499    /// ensure that it is unconditionally sound to have concurrent references to
500    /// both parts.
501    ///
502    /// When possible, you should prefer using [`Self::via_into_bytes`], which
503    /// ensures this safety property through regular trait bounds.
504    ///
505    /// # Examples
506    ///
507    /// In the below example, a single byte of padding exists (on most
508    /// platforms) between `Packet<[u16]>`'s `length` and `body` fields,
509    /// precluding the use of [`Self::via_into_bytes`].
510    ///
511    /// ```
512    /// use zerocopy::SplitAt;
513    /// # use zerocopy_derive::*;
514    ///
515    /// #[derive(SplitAt, KnownLayout)]
516    /// #[repr(C)]
517    /// struct Packet<B: ?Sized> {
518    ///     length: u8,
519    ///     body: B,
520    /// }
521    ///
522    /// let packet: &Packet<[u16]> = &Packet { length: 4, body: [1u16, 2, 3, 4, 5, 6, 7, 8, 9] };
523    ///
524    /// assert_eq!(packet.length, 4);
525    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
526    ///
527    /// if let Some(split) = packet.split_at(packet.length as usize) {
528    ///     // Every body length requires no trailing padding.
529    ///     let (packet, rest) = split.via_no_dynamic_padding();
530    ///     assert_eq!(packet.length, 4);
531    ///     assert_eq!(packet.body, [1, 2, 3, 4]);
532    ///     assert_eq!(rest, [5, 6, 7, 8, 9]);
533    /// } else {
534    ///     unreachable!("The packet's length field is within its body");
535    /// }
536    /// ```
537    ///
538    /// # Compile-Time Assertions
539    ///
540    /// This method rejects at compile-time any type that admits dynamic
541    /// trailing padding. In the below example, some `split_at` indices would
542    /// produce left parts whose trailing padding overlaps with the right part:
543    ///
544    /// ```compile_fail,E0080
545    /// use zerocopy::SplitAt;
546    /// # use zerocopy_derive::*;
547    ///
548    /// #[derive(SplitAt, KnownLayout)]
549    /// #[repr(C, align(2))]
550    /// struct Packet<B: ?Sized> {
551    ///     length: u16,
552    ///     body: B,
553    /// }
554    ///
555    /// let packet: &Packet<[u8]> = &Packet { length: 4, body: [1u8, 2, 3, 4, 5, 6, 7, 8, 9] };
556    ///
557    /// if let Some(split) = packet.split_at(packet.length as usize) {
558    ///     let _ = split.via_no_dynamic_padding(); // ⚠ Compile Error!
559    /// } else {
560    ///     unreachable!("The packet's length field is within its body");
561    /// }
562    /// ```
563    ///
564    /// If you need to split such types, use [`Self::via_runtime_check`].
565    ///
566    #[doc = codegen_header!("h5", "split_via_no_dynamic_padding")]
567    ///
568    /// See [`Split::via_immutable`](#method.split_via_immutable.codegen).
569    #[must_use = "has no side effects"]
570    #[inline(always)]
571    pub fn via_no_dynamic_padding(self) -> (&'a T, &'a [T::Elem]) {
572        let (l, r) = self.into_ptr().via_no_dynamic_padding();
573        (l.as_ref(), r.as_ref())
574    }
575
576    /// Produces the split parts of `self`, using a dynamic check to ensure that
577    /// it is sound to have concurrent references to both parts. You should
578    /// prefer using [`Self::via_immutable`], [`Self::via_into_bytes`], or
579    /// [`Self::via_no_dynamic_padding`], which perform no runtime check.
580    ///
581    /// Note that this check is overly conservative if `T` is [`Immutable`]; for
582    /// some types, this check will reject some splits which
583    /// [`Self::via_immutable`] will accept.
584    ///
585    /// # Examples
586    ///
587    /// ```
588    /// use zerocopy::SplitAt;
589    /// # use zerocopy_derive::*;
590    ///
591    /// #[derive(SplitAt, KnownLayout)]
592    /// #[repr(C, align(2))]
593    /// struct Packet<B: ?Sized> {
594    ///     length: u16,
595    ///     body: B,
596    /// }
597    ///
598    /// let packet: &Packet<[u8]> = &Packet { length: 4, body: [1u8, 2, 3, 4, 5, 6, 7, 8, 9] };
599    ///
600    /// assert_eq!(packet.length, 4);
601    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
602    ///
603    /// // The two-byte prefix and four-byte body need no trailing padding.
604    /// if let Some(split) = packet.split_at(packet.length as usize) {
605    ///     if let Ok((packet, rest)) = split.via_runtime_check() {
606    ///         assert_eq!(packet.length, 4);
607    ///         assert_eq!(packet.body, [1, 2, 3, 4]);
608    ///         assert_eq!(rest, [5, 6, 7, 8, 9]);
609    ///     } else {
610    ///         unreachable!("A four-byte body requires no trailing padding");
611    ///     }
612    /// } else {
613    ///     unreachable!("The packet's length field is within its body");
614    /// }
615    ///
616    /// // A three-byte body needs a padding byte that would overlap `rest`.
617    /// if let Some(split) = packet.split_at((packet.length - 1) as usize) {
618    ///     assert!(split.via_runtime_check().is_err());
619    /// } else {
620    ///     unreachable!("One less than the packet's length is within its body");
621    /// }
622    /// ```
623    ///
624    #[doc = codegen_section!(
625        header = "h5",
626        bench = "split_via_runtime_check",
627        format = "coco",
628        arity = 2,
629        [
630            open
631            @index 1
632            @title "Unsized"
633            @variant "dynamic_size"
634        ],
635        [
636            @index 2
637            @title "Dynamically Padded"
638            @variant "dynamic_padding"
639        ]
640    )]
641    #[must_use = "has no side effects"]
642    #[inline(always)]
643    pub fn via_runtime_check(self) -> Result<(&'a T, &'a [T::Elem]), Self> {
644        match self.into_ptr().via_runtime_check() {
645            Ok((l, r)) => Ok((l.as_ref(), r.as_ref())),
646            Err(s) => Err(s.into_ref()),
647        }
648    }
649
650    /// Unsafely produces the split parts of `self`.
651    ///
652    /// # Safety
653    ///
654    /// If `T` permits interior mutation, the trailing padding bytes of the left
655    /// portion must not overlap the right portion. For some dynamically sized
656    /// types, the padding that appears after the trailing slice field [is a
657    /// dynamic function of the trailing slice
658    /// length](KnownLayout#slice-dst-layout). Thus, for some types, this
659    /// condition is dependent on the length of the left portion.
660    ///
661    #[doc = codegen_section!(
662        header = "h5",
663        bench = "split_via_unchecked",
664        format = "coco",
665        arity = 2,
666        [
667            open
668            @index 1
669            @title "Unsized"
670            @variant "dynamic_size"
671        ],
672        [
673            @index 2
674            @title "Dynamically Padded"
675            @variant "dynamic_padding"
676        ]
677    )]
678    #[must_use = "has no side effects"]
679    #[inline(always)]
680    pub unsafe fn via_unchecked(self) -> (&'a T, &'a [T::Elem]) {
681        // SAFETY: The aliasing of `self.into_ptr()` is not `Exclusive`, but the
682        // caller has promised that if `T` permits interior mutation then the
683        // left and right portions of `self` split at `l_len` do not overlap.
684        let (l, r) = unsafe { self.into_ptr().via_unchecked() };
685        (l.as_ref(), r.as_ref())
686    }
687}
688
689impl<'a, T> Split<&'a mut T>
690where
691    T: ?Sized + SplitAt,
692{
693    #[inline(always)]
694    fn into_ptr(self) -> Split<Ptr<'a, T, (Exclusive, Aligned, Safe)>> {
695        let source = Ptr::from_mut(self.source);
696        // SAFETY: `Ptr::from_mut(self.source)` points to exactly `self.source`,
697        // and thus maintains the invariants of `self` with respect to `l_len`.
698        unsafe { Split::new(source, self.l_len) }
699    }
700
701    /// Produces the split parts of `self`, using [`IntoBytes`] to ensure that
702    /// it is sound to have concurrent references to both parts.
703    ///
704    /// # Examples
705    ///
706    /// ```
707    /// use zerocopy::{SplitAt, FromBytes};
708    /// # use zerocopy_derive::*;
709    ///
710    /// #[derive(SplitAt, FromBytes, KnownLayout, IntoBytes)]
711    /// #[repr(C)]
712    /// struct Packet<B: ?Sized> {
713    ///     length: u8,
714    ///     body: B,
715    /// }
716    ///
717    /// // These bytes encode a `Packet`.
718    /// let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
719    ///
720    /// let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap();
721    ///
722    /// assert_eq!(packet.length, 4);
723    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
724    ///
725    /// {
726    ///     // Attempt to split `packet` at `length`.
727    ///     let split = packet.split_at_mut(packet.length as usize).unwrap();
728    ///
729    ///     // Use the `IntoBytes` bound on `Packet` to prove that it's okay to
730    ///     // return concurrent references to `packet` and `rest`.
731    ///     let (packet, rest) = split.via_into_bytes();
732    ///
733    ///     assert_eq!(packet.length, 4);
734    ///     assert_eq!(packet.body, [1, 2, 3, 4]);
735    ///     assert_eq!(rest, [5, 6, 7, 8, 9]);
736    ///
737    ///     rest.fill(0);
738    /// }
739    ///
740    /// assert_eq!(packet.length, 4);
741    /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]);
742    /// ```
743    ///
744    /// # Code Generation
745    ///
746    /// See [`Split::via_immutable`](#method.split_via_immutable.codegen).
747    #[must_use = "has no side effects"]
748    #[inline(always)]
749    pub fn via_into_bytes(self) -> (&'a mut T, &'a mut [T::Elem])
750    where
751        T: IntoBytes,
752    {
753        let (l, r) = self.into_ptr().via_into_bytes();
754        (l.as_mut(), r.as_mut())
755    }
756
757    /// Produces the split parts of `self` using [`Self::via_no_dynamic_padding`].
758    #[deprecated(note = "use `Split::via_no_dynamic_padding` instead")]
759    #[doc(hidden)]
760    #[must_use = "has no side effects"]
761    #[inline(always)]
762    pub fn via_unaligned(self) -> (&'a mut T, &'a mut [T::Elem])
763    where
764        T: Unaligned,
765    {
766        self.via_no_dynamic_padding()
767    }
768
769    /// Produces the split parts of `self` using a compile-time assertion to
770    /// ensure that it is unconditionally sound to have concurrent references to
771    /// both parts.
772    ///
773    /// When possible, you should prefer using [`Self::via_into_bytes`], which
774    /// ensures this safety property through regular trait bounds.
775    ///
776    /// # Examples
777    ///
778    /// In the below example, a single byte of padding exists (on most
779    /// platforms) between `Packet<[u16]>`'s `length` and `body` fields,
780    /// precluding the use of [`Self::via_into_bytes`].
781    ///
782    /// ```
783    /// use zerocopy::SplitAt;
784    /// # use zerocopy_derive::*;
785    ///
786    /// #[derive(SplitAt, KnownLayout)]
787    /// #[repr(C)]
788    /// struct Packet<B: ?Sized> {
789    ///     length: u8,
790    ///     body: B,
791    /// }
792    ///
793    /// let packet: &mut Packet<[u16]> = &mut Packet { length: 4, body: [1u16, 2, 3, 4, 5, 6, 7, 8, 9] };
794    ///
795    /// assert_eq!(packet.length, 4);
796    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
797    ///
798    /// // Every body length requires no trailing padding.
799    /// if let Some(split) = packet.split_at_mut(packet.length as usize) {
800    ///     let (packet, rest) = split.via_no_dynamic_padding();
801    ///     assert_eq!(packet.length, 4);
802    ///     assert_eq!(packet.body, [1, 2, 3, 4]);
803    ///     assert_eq!(rest, [5, 6, 7, 8, 9]);
804    ///     rest.fill(0);
805    /// } else {
806    ///     unreachable!("The packet's length field is within its body");
807    /// }
808    ///
809    /// assert_eq!(packet.length, 4);
810    /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]);
811    /// ```
812    ///
813    /// # Compile-Time Assertions
814    ///
815    /// This method rejects at compile-time any type that admits dynamic
816    /// trailing padding. In the below example, some `split_at` indices would
817    /// produce left parts whose trailing padding overlaps with the right part:
818    ///
819    /// ```compile_fail,E0080
820    /// use zerocopy::SplitAt;
821    /// # use zerocopy_derive::*;
822    ///
823    /// #[derive(SplitAt, KnownLayout)]
824    /// #[repr(C, align(2))]
825    /// struct Packet<B: ?Sized> {
826    ///     length: u16,
827    ///     body: B,
828    /// }
829    ///
830    /// let packet: &mut Packet<[u8]> = &mut Packet { length: 4, body: [1u8, 2, 3, 4, 5, 6, 7, 8, 9] };
831    ///
832    /// if let Some(split) = packet.split_at_mut(packet.length as usize) {
833    ///     let _ = split.via_no_dynamic_padding(); // ⚠ Compile Error!
834    /// } else {
835    ///     unreachable!("The packet's length field is within its body");
836    /// }
837    /// ```
838    ///
839    /// If you need to split such types, use [`Self::via_runtime_check`].
840    ///
841    /// # Code Generation
842    ///
843    /// See [`Split::via_immutable`](#method.split_via_immutable.codegen).
844    #[must_use = "has no side effects"]
845    #[inline(always)]
846    pub fn via_no_dynamic_padding(self) -> (&'a mut T, &'a mut [T::Elem]) {
847        let (l, r) = self.into_ptr().via_no_dynamic_padding();
848        (l.as_mut(), r.as_mut())
849    }
850
851    /// Produces the split parts of `self`, using a dynamic check to ensure that
852    /// it is sound to have concurrent references to both parts. You should
853    /// prefer using [`Self::via_into_bytes`] or
854    /// [`Self::via_no_dynamic_padding`], which perform no runtime check.
855    ///
856    /// # Examples
857    ///
858    /// ```
859    /// use zerocopy::SplitAt;
860    /// # use zerocopy_derive::*;
861    ///
862    /// #[derive(SplitAt, KnownLayout)]
863    /// #[repr(C, align(2))]
864    /// struct Packet<B: ?Sized> {
865    ///     length: u16,
866    ///     body: B,
867    /// }
868    ///
869    /// let packet: &mut Packet<[u8]> = &mut Packet { length: 4, body: [1u8, 2, 3, 4, 5, 6, 7, 8, 9] };
870    ///
871    /// assert_eq!(packet.length, 4);
872    /// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
873    ///
874    /// // The two-byte prefix and four-byte body need no trailing padding.
875    /// if let Some(split) = packet.split_at_mut(packet.length as usize) {
876    ///     if let Ok((packet, rest)) = split.via_runtime_check() {
877    ///         assert_eq!(packet.length, 4);
878    ///         assert_eq!(packet.body, [1, 2, 3, 4]);
879    ///         assert_eq!(rest, [5, 6, 7, 8, 9]);
880    ///         rest.fill(0);
881    ///     } else {
882    ///         unreachable!("A four-byte body requires no trailing padding");
883    ///     }
884    /// } else {
885    ///     unreachable!("The packet's length field is within its body");
886    /// }
887    ///
888    /// assert_eq!(packet.length, 4);
889    /// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]);
890    /// ```
891    ///
892    /// # Code Generation
893    ///
894    /// See [`Split::via_runtime_check`](#method.split_via_runtime_check.codegen).
895    #[must_use = "has no side effects"]
896    #[inline(always)]
897    pub fn via_runtime_check(self) -> Result<(&'a mut T, &'a mut [T::Elem]), Self> {
898        match self.into_ptr().via_runtime_check() {
899            Ok((l, r)) => Ok((l.as_mut(), r.as_mut())),
900            Err(s) => Err(s.into_mut()),
901        }
902    }
903
904    /// Unsafely produces the split parts of `self`.
905    ///
906    /// # Safety
907    ///
908    /// The trailing padding bytes of the left portion must not overlap the
909    /// right portion. For some dynamically sized types, the padding that
910    /// appears after the trailing slice field [is a dynamic function of the
911    /// trailing slice length](KnownLayout#slice-dst-layout). Thus, for some
912    /// types, this condition is dependent on the length of the left portion.
913    ///
914    /// # Code Generation
915    ///
916    /// See [`Split::via_unchecked`](#method.split_via_unchecked.codegen).
917    #[must_use = "has no side effects"]
918    #[inline(always)]
919    pub unsafe fn via_unchecked(self) -> (&'a mut T, &'a mut [T::Elem]) {
920        // SAFETY: The aliasing of `self.into_ptr()` is `Exclusive`, and the
921        // caller has promised that the left and right portions of `self` split
922        // at `l_len` do not overlap.
923        let (l, r) = unsafe { self.into_ptr().via_unchecked() };
924        (l.as_mut(), r.as_mut())
925    }
926}
927
928impl<'a, T, I> Split<Ptr<'a, T, I>>
929where
930    T: ?Sized + SplitAt,
931    I: Invariants<Alignment = Aligned, Validity = Safe>,
932{
933    fn into_ref(self) -> Split<&'a T>
934    where
935        I: Invariants<Aliasing = Shared>,
936    {
937        // SAFETY: `self.source.as_ref()` points to exactly the same referent as
938        // `self.source` and thus maintains the invariants of `self` with
939        // respect to `l_len`.
940        unsafe { Split::new(self.source.as_ref(), self.l_len) }
941    }
942
943    fn into_mut(self) -> Split<&'a mut T>
944    where
945        I: Invariants<Aliasing = Exclusive>,
946    {
947        // SAFETY: `self.source.as_mut()` points to exactly the same referent as
948        // `self.source` and thus maintains the invariants of `self` with
949        // respect to `l_len`.
950        unsafe { Split::new(self.source.unify_invariants().as_mut(), self.l_len) }
951    }
952
953    /// Produces the length of `self`'s left part.
954    #[inline(always)]
955    fn l_len(&self) -> MetadataOf<T> {
956        // SAFETY: By invariant on `Split`, `self.l_len` is not greater than the
957        // length of `self.source`.
958        unsafe { MetadataOf::<T>::new_unchecked(self.l_len) }
959    }
960
961    /// Produces the split parts of `self`, using [`Immutable`] to ensure that
962    /// it is sound to have concurrent references to both parts.
963    #[inline(always)]
964    fn via_immutable(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>)
965    where
966        T: Immutable,
967        I: Invariants<Aliasing = Shared>,
968    {
969        // SAFETY: `Aliasing = Shared` and `T: Immutable`.
970        unsafe { self.via_unchecked() }
971    }
972
973    /// Produces the split parts of `self`, using [`IntoBytes`] to ensure that
974    /// it is sound to have concurrent references to both parts.
975    #[inline(always)]
976    fn via_into_bytes(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>)
977    where
978        T: IntoBytes,
979    {
980        // SAFETY: By `T: IntoBytes`, `T` has no padding for any length.
981        // Consequently, `T` can be split into non-overlapping parts at any
982        // index.
983        unsafe { self.via_unchecked() }
984    }
985
986    /// Produces the split parts of `self` after the conservative layout
987    /// predicate establishes that `T` never requires dynamic trailing padding.
988    #[inline(always)]
989    fn via_no_dynamic_padding(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) {
990        static_assert!(
991            T: ?Sized + KnownLayout => !T::LAYOUT.requires_dynamic_padding(),
992            "`Split::via_no_dynamic_padding` cannot be used with a type whose layout may require dynamic trailing padding; use `Split::via_runtime_check` instead"
993        );
994
995        // SAFETY: The assertion establishes that `requires_dynamic_padding()`
996        // is false. By that method's guarantee, every valid metadata—including
997        // `self.l_len()`, which is valid by `Split`'s invariant—describes an
998        // object with no trailing padding. By the postcondition of
999        // `PtrInner::split_at_unchecked`, the two returned referents are then
1000        // contiguous and non-overlapping. Since the source already conforms to
1001        // `I::Aliasing`, splitting it into disjoint byte ranges preserves that
1002        // invariant: under `Exclusive`, neither result aliases or accesses the
1003        // other's bytes; under `Shared`, interior mutation through one result
1004        // cannot mutate bytes pointed to by the other. This satisfies Rust's
1005        // reference aliasing rules [1].
1006        //
1007        // [1] Per https://doc.rust-lang.org/1.93.1/std/ptr/index.html#pointer-to-reference-conversion:
1008        //
1009        //   When creating a mutable reference, then while this reference
1010        //   exists, the memory it points to must not get accessed (read or
1011        //   written) through any other pointer or reference not derived from
1012        //   this reference.
1013        //
1014        //   When creating a shared reference, then while this reference
1015        //   exists, the memory it points to must not get mutated (except inside
1016        //   `UnsafeCell`).
1017        unsafe { self.via_unchecked() }
1018    }
1019
1020    /// Produces the split parts of `self`, using a dynamic check to ensure that
1021    /// it is sound to have concurrent references to both parts. You should
1022    /// prefer using [`Self::via_immutable`], [`Self::via_into_bytes`], or
1023    /// [`Self::via_no_dynamic_padding`], which perform no runtime check.
1024    #[inline(always)]
1025    fn via_runtime_check(self) -> Result<(Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>), Self> {
1026        let l_len = self.l_len();
1027        // `l_len` witnesses an object size at most `isize::MAX`, and
1028        // `KnownLayout::LAYOUT` guarantees that it contains the trailing
1029        // slice. Thus `padding_for_elems` returns the exact trailing padding.
1030        let trailing_padding = crate::trailing_slice_layout::<T>().padding_for_elems(l_len.get());
1031        // FIXME(#1290): Once we require `KnownLayout` on all fields, add an
1032        // `IS_IMMUTABLE` associated const, and add `T::IS_IMMUTABLE ||` to the
1033        // below check.
1034        if trailing_padding == 0 {
1035            // SAFETY: As established above, `trailing_padding` is the exact
1036            // padding after the left part's trailing slice. If it is zero,
1037            // the left and right parts are strictly non-overlapping.
1038            Ok(unsafe { self.via_unchecked() })
1039        } else {
1040            Err(self)
1041        }
1042    }
1043
1044    /// Unsafely produces the split parts of `self`.
1045    ///
1046    /// # Safety
1047    ///
1048    /// The caller promises that if `I::Aliasing` is [`Exclusive`] or `T`
1049    /// permits interior mutation, then the left part has no trailing padding.
1050    #[inline(always)]
1051    unsafe fn via_unchecked(self) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>) {
1052        let l_len = self.l_len();
1053        let inner = self.source.as_inner();
1054
1055        // SAFETY: By invariant on `Self::l_len`, `l_len` is not greater than
1056        // the length of `inner`'s trailing slice.
1057        let (left, right) = unsafe { inner.split_at_unchecked(l_len) };
1058
1059        // Lemma 0: `left` and `right` conform to the aliasing invariant
1060        // `I::Aliasing`. Proof: If `I::Aliasing` is `Exclusive` or `T` permits
1061        // interior mutation, the caller promises that the left part has no
1062        // trailing padding. Consequently, by the postcondition of
1063        // `PtrInner::split_at_unchecked`, `left` and `right` do not overlap.
1064        // If `I::Aliasing` is shared and `T` forbids interior mutation, then
1065        // overlap between their referents is permissible.
1066
1067        // SAFETY:
1068        // 0. `left` conforms to the aliasing invariant of `I::Aliasing`, by Lemma 0.
1069        // 1. `left` conforms to the alignment invariant of `I::Alignment, because
1070        //    the referents of `left` and `Self` have the same address and type
1071        //    (and, thus, alignment requirement).
1072        // 2. `left` conforms to the validity invariant of `I::Validity`, neither
1073        //    the type nor bytes of `left`'s referent have been changed.
1074        let left = unsafe { Ptr::from_inner(left) };
1075
1076        // SAFETY:
1077        // 0. `right` conforms to the aliasing invariant of `I::Aliasing`, by Lemma
1078        //    0.
1079        // 1. `right` conforms to the alignment invariant of `I::Alignment`:
1080        //    if the source is aligned, `T: SplitAt` guarantees that its
1081        //    trailing slice's address is aligned for `T::Elem`. Advancing by
1082        //    whole elements preserves that alignment.
1083        // 2. `right` conforms to the validity invariant of `I::Validity`,
1084        //    because `T: SplitAt` guarantees that `T::Elem` has the size and
1085        //    bit validity of the original trailing element. It also guarantees
1086        //    compatible shared and mutable access, so writes through `right`
1087        //    preserve the original elements' validity and interior mutation
1088        //    respects the original `UnsafeCell` coverage. The left part
1089        //    cannot invalidate `right`: when the references are exclusive or
1090        //    permit interior mutation, the caller guarantees no trailing
1091        //    padding and hence no overlap.
1092        let right = unsafe { Ptr::from_inner(right) };
1093
1094        (left, right)
1095    }
1096}
1097
1098#[cfg(test)]
1099mod tests {
1100    use core::{cell::Cell, mem::ManuallyDrop};
1101
1102    use crate::{Immutable, KnownLayout, SplitAt, Unalign, Unaligned};
1103
1104    #[derive(KnownLayout, SplitAt, Immutable, Unaligned)]
1105    #[repr(C, packed)]
1106    struct Packed<T: ?Sized> {
1107        prefix: u8,
1108        tail: ManuallyDrop<T>,
1109    }
1110
1111    #[derive(KnownLayout, SplitAt, Immutable)]
1112    #[repr(C, packed(2))]
1113    struct Packed2<T: ?Sized> {
1114        prefix: u8,
1115        tail: ManuallyDrop<T>,
1116    }
1117
1118    #[derive(KnownLayout, SplitAt, Immutable)]
1119    #[repr(C)]
1120    struct Inner<T: ?Sized> {
1121        prefix: u32,
1122        tail: T,
1123    }
1124
1125    #[test]
1126    fn test_split_at_packed() {
1127        use crate::{FromBytes, IntoBytes};
1128
1129        #[derive(FromBytes, IntoBytes, KnownLayout, SplitAt, Immutable, Unaligned)]
1130        #[repr(C, packed)]
1131        struct Packet {
1132            prefix: u8,
1133            tail: [u16],
1134        }
1135
1136        // The tail starts at an odd address, exercising unaligned reads and
1137        // writes on targets where `u16` has alignment 2.
1138        #[repr(align(8))]
1139        struct Bytes([u8; 9]);
1140
1141        for i in 0..=4 {
1142            let mut bytes = Bytes([1; 9]);
1143            let packet = Packet::ref_from_bytes(&bytes.0).unwrap();
1144            let (left, right): (&Packet, &[Unalign<u16>]) =
1145                packet.split_at(i).unwrap().via_immutable();
1146            assert_eq!(core::mem::size_of_val(left), 1 + 2 * i);
1147            assert_eq!(right.len(), 4 - i);
1148            assert!(right.iter().all(|elem| elem.get() == 0x0101));
1149            assert!(left.split_at(i).is_some());
1150            assert!(left.split_at(i + 1).is_none());
1151            assert!(packet.split_at(5).is_none());
1152
1153            let (_, right) = packet.split_at(i).unwrap().via_into_bytes();
1154            assert_eq!(right.len(), 4 - i);
1155            let (_, right) = packet.split_at(i).unwrap().via_no_dynamic_padding();
1156            assert_eq!(right.len(), 4 - i);
1157
1158            let packet = Packet::mut_from_bytes(&mut bytes.0).unwrap();
1159            let (left, right): (&mut Packet, &mut [Unalign<u16>]) =
1160                packet.split_at_mut(i).unwrap().via_runtime_check().ok().unwrap();
1161            left.prefix = 2;
1162            for elem in right {
1163                *elem = Unalign::new(0x0202);
1164            }
1165            assert_eq!(bytes.0[0], 2);
1166            assert!(bytes.0[1..1 + 2 * i].iter().all(|&byte| byte == 1));
1167            assert!(bytes.0[1 + 2 * i..].iter().all(|&byte| byte == 2));
1168        }
1169    }
1170
1171    #[test]
1172    fn test_split_at_nested_packed() {
1173        // A packing factor greater than 1 still exposes `Unalign` elements,
1174        // including when the factor is below the original element alignment.
1175        let mut words = Packed2 { prefix: 0, tail: ManuallyDrop::new([1u32, 2, 3]) };
1176        let dst: &mut Packed2<[u32]> = &mut words;
1177        let (left, right): (&mut _, &mut [Unalign<u32>]) =
1178            dst.split_at_mut(1).unwrap().via_no_dynamic_padding();
1179        left.prefix = 4;
1180        right[0] = Unalign::new(5);
1181        let dst: &Packed2<[u32]> = &words;
1182        let (left, right) = dst.split_at(0).unwrap().via_immutable();
1183        assert_eq!(left.prefix, 4);
1184        assert_eq!(right[0].get(), 1);
1185        assert_eq!(right[1].get(), 5);
1186        assert_eq!(right[2].get(), 3);
1187
1188        let mut packet = Inner {
1189            prefix: 0,
1190            tail: Packed2 {
1191                prefix: 1,
1192                tail: ManuallyDrop::new(Packed {
1193                    prefix: 2,
1194                    tail: ManuallyDrop::new([3u16, 4, 5]),
1195                }),
1196            },
1197        };
1198        let dst: &Inner<Packed2<Packed<[u16]>>> = &packet;
1199        let (left, right): (&_, &[Unalign<Unalign<u16>>]) =
1200            dst.split_at(1).unwrap().via_immutable();
1201        assert_eq!(left.prefix, 0);
1202        assert_eq!(right.len(), 2);
1203        assert_eq!(right[0].get().get(), 4);
1204        assert_eq!(right[1].get().get(), 5);
1205
1206        // Split the packed field separately: the unpacked outer struct's
1207        // padding does not constrain this split.
1208        let dst: &mut Packed2<Packed<[u16]>> = &mut packet.tail;
1209        let (left, right): (&mut _, &mut [Unalign<Unalign<u16>>]) =
1210            dst.split_at_mut(1).unwrap().via_no_dynamic_padding();
1211        left.prefix = 6;
1212        right[0] = Unalign::new(Unalign::new(7));
1213        let dst: &Inner<Packed2<Packed<[u16]>>> = &packet;
1214        let (_, right) = dst.split_at(0).unwrap().via_immutable();
1215        assert_eq!(right[0].get().get(), 3);
1216        assert_eq!(right[1].get().get(), 7);
1217        assert_eq!(right[2].get().get(), 5);
1218    }
1219
1220    #[test]
1221    fn test_split_at_packed_preserves_inner_padding() {
1222        for i in 0..=4 {
1223            let mut packet = Packed {
1224                prefix: 1,
1225                tail: ManuallyDrop::new(Inner { prefix: 0, tail: [2u8, 3, 4, 5] }),
1226            };
1227            let dst: &Packed<Inner<[u8]>> = &packet;
1228            let (left, right): (&_, &[Unalign<u8>]) = dst.split_at(i).unwrap().via_immutable();
1229            assert_eq!(right.len(), 4 - i);
1230            assert_eq!(right.first().map(Unalign::get), [2, 3, 4, 5].get(i).copied());
1231
1232            // The inner `u32` prefix makes the tail start at byte 5 of the
1233            // packed wrapper. Its size may still include inner padding.
1234            let has_padding = core::mem::size_of_val(left) != 5 + i;
1235            assert_eq!(dst.split_at(i).unwrap().via_runtime_check().is_err(), has_padding);
1236
1237            let dst: &mut Packed<Inner<[u8]>> = &mut packet;
1238            let split = dst.split_at_mut(i).unwrap().via_runtime_check();
1239            assert_eq!(split.is_err(), has_padding);
1240            if let Ok((left, right)) = split {
1241                left.prefix = 6;
1242                for elem in right {
1243                    *elem = Unalign::new(7);
1244                }
1245                let dst: &Packed<Inner<[u8]>> = &packet;
1246                let (left, right) = dst.split_at(i).unwrap().via_immutable();
1247                assert_eq!(left.prefix, 6);
1248                assert!(right.iter().all(|elem| elem.get() == 7));
1249            }
1250        }
1251    }
1252
1253    #[test]
1254    fn test_split_at_packed_interior_mutation_and_zsts() {
1255        let packet = Packed {
1256            prefix: 0,
1257            tail: ManuallyDrop::new([Cell::new(1u8), Cell::new(2), Cell::new(3)]),
1258        };
1259        let dst: &Packed<[Cell<u8>]> = &packet;
1260        let (left, right): (&_, &[Unalign<Cell<u8>>]) =
1261            dst.split_at(1).unwrap().via_no_dynamic_padding();
1262        left.tail[0].set(4);
1263        right[0].try_deref().unwrap().set(5);
1264        assert_eq!(dst.tail[0].get(), 4);
1265        assert_eq!(dst.tail[1].get(), 5);
1266        assert_eq!(dst.tail[2].get(), 3);
1267
1268        let mut packet = Packed { prefix: 0, tail: ManuallyDrop::new([(); 3]) };
1269        for i in 0..=3 {
1270            let dst: &mut Packed<[()]> = &mut packet;
1271            let (left, right): (&mut _, &mut [Unalign<()>]) =
1272                dst.split_at_mut(i).unwrap().via_no_dynamic_padding();
1273            assert_eq!(left.tail.len(), i);
1274            assert_eq!(right.len(), 3 - i);
1275            assert_eq!(core::mem::size_of_val(left), 1);
1276        }
1277    }
1278
1279    #[cfg(feature = "derive")]
1280    #[test]
1281    fn test_split_at() {
1282        use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt};
1283
1284        #[derive(FromBytes, KnownLayout, SplitAt, IntoBytes, Immutable, Debug)]
1285        #[repr(C)]
1286        struct SliceDst<const OFFSET: usize> {
1287            prefix: [u8; OFFSET],
1288            trailing: [u8],
1289        }
1290
1291        #[allow(clippy::as_conversions)]
1292        fn test_split_at<const OFFSET: usize, const BUFFER_SIZE: usize>() {
1293            // Test `split_at`
1294            let n: usize = BUFFER_SIZE - OFFSET;
1295            let arr = [1; BUFFER_SIZE];
1296            let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap();
1297            for i in 0..=n {
1298                let (l, r) = dst.split_at(i).unwrap().via_runtime_check().unwrap();
1299                let l_sum: u8 = l.trailing.iter().sum();
1300                let r_sum: u8 = r.iter().sum();
1301                assert_eq!(l_sum, i as u8);
1302                assert_eq!(r_sum, (n - i) as u8);
1303                assert_eq!(l_sum + r_sum, n as u8);
1304            }
1305
1306            // Test `split_at_mut`
1307            let n: usize = BUFFER_SIZE - OFFSET;
1308            let mut arr = [1; BUFFER_SIZE];
1309            let dst = SliceDst::<OFFSET>::mut_from_bytes(&mut arr[..]).unwrap();
1310            for i in 0..=n {
1311                let (l, r) = dst.split_at_mut(i).unwrap().via_runtime_check().unwrap();
1312                let l_sum: u8 = l.trailing.iter().sum();
1313                let r_sum: u8 = r.iter().sum();
1314                assert_eq!(l_sum, i as u8);
1315                assert_eq!(r_sum, (n - i) as u8);
1316                assert_eq!(l_sum + r_sum, n as u8);
1317            }
1318        }
1319
1320        test_split_at::<0, 16>();
1321        test_split_at::<1, 17>();
1322        test_split_at::<2, 18>();
1323    }
1324
1325    #[cfg(feature = "derive")]
1326    #[test]
1327    #[allow(clippy::as_conversions)]
1328    fn test_split_at_overlapping() {
1329        use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt};
1330
1331        #[derive(FromBytes, KnownLayout, SplitAt, Immutable)]
1332        #[repr(C, align(2))]
1333        struct SliceDst {
1334            prefix: u8,
1335            trailing: [u8],
1336        }
1337
1338        assert!(SliceDst::LAYOUT.requires_dynamic_padding());
1339
1340        const N: usize = 16;
1341
1342        let arr = [1u16; N];
1343        let dst = SliceDst::ref_from_bytes(arr.as_bytes()).unwrap();
1344
1345        for i in 0..N {
1346            let split = dst.split_at(i).unwrap().via_runtime_check();
1347            if i % 2 == 1 {
1348                assert!(split.is_ok());
1349            } else {
1350                assert!(split.is_err());
1351            }
1352        }
1353    }
1354    #[test]
1355    fn test_split_at_unchecked() {
1356        use crate::SplitAt;
1357        let mut arr = [1, 2, 3, 4];
1358        let slice = &arr[..];
1359        // SAFETY: 2 <= arr.len() (4)
1360        let split = unsafe { SplitAt::split_at_unchecked(slice, 2) };
1361        // SAFETY: SplitAt::split_at_unchecked guarantees that the split is valid.
1362        let (l, r) = unsafe { split.via_unchecked() };
1363        assert_eq!(l, &[1, 2]);
1364        assert_eq!(r, &[3, 4]);
1365
1366        let slice_mut = &mut arr[..];
1367        // SAFETY: 2 <= arr.len() (4)
1368        let split = unsafe { SplitAt::split_at_mut_unchecked(slice_mut, 2) };
1369        // SAFETY: SplitAt::split_at_mut_unchecked guarantees that the split is valid.
1370        let (l, r) = unsafe { split.via_unchecked() };
1371        assert_eq!(l, &mut [1, 2]);
1372        assert_eq!(r, &mut [3, 4]);
1373    }
1374
1375    #[test]
1376    fn test_split_at_via_methods() {
1377        use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt};
1378        #[derive(FromBytes, KnownLayout, SplitAt, IntoBytes, Immutable, Debug)]
1379        #[repr(C)]
1380        struct Packet {
1381            length: u8,
1382            body: [u8],
1383        }
1384
1385        let arr = [1, 2, 3, 4];
1386        let packet = Packet::ref_from_bytes(&arr[..]).unwrap();
1387
1388        let split1 = packet.split_at(2).unwrap();
1389        let (l, r) = split1.via_immutable();
1390        assert_eq!(l.length, 1);
1391        assert_eq!(r, &[4]);
1392
1393        let split2 = packet.split_at(2).unwrap();
1394        let (l, r) = split2.via_into_bytes();
1395        assert_eq!(l.length, 1);
1396        assert_eq!(r, &[4]);
1397    }
1398    #[test]
1399    #[allow(deprecated)]
1400    fn test_split_at_via_unaligned() {
1401        use crate::{Immutable, KnownLayout, Split, SplitAt, Unaligned};
1402
1403        fn via_unaligned<'a, T>(split: Split<&'a T>) -> (&'a T, &'a [T::Elem])
1404        where
1405            T: ?Sized + SplitAt + Unaligned,
1406        {
1407            split.via_unaligned()
1408        }
1409
1410        fn via_unaligned_mut<'a, T>(split: Split<&'a mut T>) -> (&'a mut T, &'a mut [T::Elem])
1411        where
1412            T: ?Sized + SplitAt + Unaligned,
1413        {
1414            split.via_unaligned()
1415        }
1416
1417        #[derive(KnownLayout, SplitAt, Immutable, Unaligned)]
1418        #[repr(C)]
1419        struct Packet<B: ?Sized> {
1420            prefix: [u8; 2],
1421            body: B,
1422        }
1423
1424        // Exercise generic callers using the original `T: Unaligned` bound.
1425        assert!(!Packet::<[[u8; 2]]>::LAYOUT.requires_dynamic_padding());
1426        let packet = Packet { prefix: [0, 1], body: [[2, 3], [4, 5], [6, 7]] };
1427        let packet: &Packet<[[u8; 2]]> = &packet;
1428
1429        let split = packet.split_at(2).unwrap();
1430        let (l, r) = via_unaligned(split);
1431        assert_eq!(l.body, [[2, 3], [4, 5]]);
1432        assert_eq!(r, &[[6, 7]]);
1433
1434        let mut packet = Packet { prefix: [0, 1], body: [[2, 3], [4, 5], [6, 7]] };
1435        {
1436            let packet: &mut Packet<[[u8; 2]]> = &mut packet;
1437            let split = packet.split_at_mut(2).unwrap();
1438            let (l, r) = via_unaligned_mut(split);
1439            l.body[0] = [8, 9];
1440            r[0] = [10, 11];
1441        }
1442        assert_eq!(packet.body, [[8, 9], [4, 5], [10, 11]]);
1443    }
1444
1445    #[test]
1446    fn test_split_at_via_no_dynamic_padding() {
1447        use core::cell::Cell;
1448
1449        use crate::SplitAt;
1450
1451        // `u16` does not implement `Unaligned`, but `[u16]` never requires
1452        // dynamic trailing padding.
1453        let words = [1u16, 2, 3, 4];
1454        let split = SplitAt::split_at(&words[..], 2).unwrap();
1455        let (left, right) = split.via_no_dynamic_padding();
1456        assert_eq!(left, [1, 2]);
1457        assert_eq!(right, [3, 4]);
1458
1459        let mut words = [1u16, 2, 3, 4];
1460        let split = SplitAt::split_at_mut(&mut words[..], 2).unwrap();
1461        let (left, right) = split.via_no_dynamic_padding();
1462        left[0] = 5;
1463        right[0] = 6;
1464        assert_eq!(words, [5, 2, 6, 4]);
1465
1466        // Exercise the safety-sensitive shared route with interior mutation.
1467        let cells = [Cell::new(1u16), Cell::new(2), Cell::new(3)];
1468        let split = SplitAt::split_at(&cells[..], 2).unwrap();
1469        let (left, right) = split.via_no_dynamic_padding();
1470        left[0].set(4);
1471        right[0].set(5);
1472        assert_eq!([cells[0].get(), cells[1].get(), cells[2].get()], [4, 2, 5]);
1473    }
1474}