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