xref: /linux/rust/zerocopy/src/split_at.rs (revision 12d5fc96ebbb3b948861805b32a4c3a96105ccd9)
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 
12 use super::*;
13 use 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`.
97 pub 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.
289 unsafe 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`
312 unsafe 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)]
338 pub 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 
350 impl<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 
362 impl<'a, T> Split<&'a T>
363 where
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 
689 impl<'a, T> Split<&'a mut T>
690 where
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 
928 impl<'a, T, I> Split<Ptr<'a, T, I>>
929 where
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)]
1099 mod 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 }
1475