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