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