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