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