Coverage Report

Created: 2026-04-29 06:53

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