1 // Copyright 2024 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 use super::*; 10 use crate::pointer::{ 11 BecauseInvariantsEq, BecauseMutationCompatible, MutationCompatible, TransmuteFromPtr, 12 }; 13 14 mod def { 15 use core::marker::PhantomData; 16 17 use crate::{ 18 ByteSlice, ByteSliceMut, CloneableByteSlice, CopyableByteSlice, IntoByteSlice, 19 IntoByteSliceMut, 20 }; 21 22 /// A typed reference derived from a byte slice. 23 /// 24 /// A `Ref<B, T>` is a reference to a `T` which is stored in a byte slice, `B`. 25 /// Unlike a native reference (`&T` or `&mut T`), `Ref<B, T>` has the same 26 /// mutability as the byte slice it was constructed from (`B`). 27 /// 28 /// # Examples 29 /// 30 /// `Ref` can be used to treat a sequence of bytes as a structured type, and 31 /// to read and write the fields of that type as if the byte slice reference 32 /// were simply a reference to that type. 33 /// 34 /// ```rust 35 /// use zerocopy::*; 36 /// # use zerocopy_derive::*; 37 /// 38 /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)] 39 /// #[repr(C)] 40 /// struct UdpHeader { 41 /// src_port: [u8; 2], 42 /// dst_port: [u8; 2], 43 /// length: [u8; 2], 44 /// checksum: [u8; 2], 45 /// } 46 /// 47 /// #[derive(FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)] 48 /// #[repr(C, packed)] 49 /// struct UdpPacket { 50 /// header: UdpHeader, 51 /// body: [u8], 52 /// } 53 /// 54 /// impl UdpPacket { 55 /// pub fn parse<B: ByteSlice>(bytes: B) -> Option<Ref<B, UdpPacket>> { 56 /// Ref::from_bytes(bytes).ok() 57 /// } 58 /// } 59 /// ``` 60 pub struct Ref<B, T: ?Sized>( 61 // INVARIANTS: The referent (via `.deref`, `.deref_mut`, `.into`) byte 62 // slice is aligned to `T`'s alignment and its size corresponds to a 63 // valid size for `T`. 64 B, 65 PhantomData<T>, 66 ); 67 68 impl<B, T: ?Sized> Ref<B, T> { 69 /// Constructs a new `Ref`. 70 /// 71 /// # Safety 72 /// 73 /// `bytes` dereferences (via [`deref`], [`deref_mut`], and [`into`]) to 74 /// a byte slice which is aligned to `T`'s alignment and whose size is a 75 /// valid size for `T`. 76 /// 77 /// [`deref`]: core::ops::Deref::deref 78 /// [`deref_mut`]: core::ops::DerefMut::deref_mut 79 /// [`into`]: core::convert::Into::into 80 pub(crate) unsafe fn new_unchecked(bytes: B) -> Ref<B, T> { 81 // INVARIANTS: The caller has promised that `bytes`'s referent is 82 // validly-aligned and has a valid size. 83 Ref(bytes, PhantomData) 84 } 85 } 86 87 impl<B: ByteSlice, T: ?Sized> Ref<B, T> { 88 /// Access the byte slice as a [`ByteSlice`]. 89 /// 90 /// # Safety 91 /// 92 /// The caller promises not to call methods on the returned 93 /// [`ByteSlice`] other than `ByteSlice` methods (for example, via 94 /// `Any::downcast_ref`). 95 /// 96 /// `as_byte_slice` promises to return a `ByteSlice` whose referent is 97 /// validly-aligned for `T` and has a valid size for `T`. 98 pub(crate) unsafe fn as_byte_slice(&self) -> &impl ByteSlice { 99 // INVARIANTS: The caller promises not to call methods other than 100 // those on `ByteSlice`. Since `B: ByteSlice`, dereference stability 101 // guarantees that calling `ByteSlice` methods will not change the 102 // address or length of `self.0`'s referent. 103 // 104 // SAFETY: By invariant on `self.0`, the alignment and size 105 // post-conditions are upheld. 106 &self.0 107 } 108 } 109 110 impl<B: ByteSliceMut, T: ?Sized> Ref<B, T> { 111 /// Access the byte slice as a [`ByteSliceMut`]. 112 /// 113 /// # Safety 114 /// 115 /// The caller promises not to call methods on the returned 116 /// [`ByteSliceMut`] other than `ByteSliceMut` methods (for example, via 117 /// `Any::downcast_mut`). 118 /// 119 /// `as_byte_slice` promises to return a `ByteSlice` whose referent is 120 /// validly-aligned for `T` and has a valid size for `T`. 121 pub(crate) unsafe fn as_byte_slice_mut(&mut self) -> &mut impl ByteSliceMut { 122 // INVARIANTS: The caller promises not to call methods other than 123 // those on `ByteSliceMut`. Since `B: ByteSlice`, dereference 124 // stability guarantees that calling `ByteSlice` methods will not 125 // change the address or length of `self.0`'s referent. 126 // 127 // SAFETY: By invariant on `self.0`, the alignment and size 128 // post-conditions are upheld. 129 &mut self.0 130 } 131 } 132 133 impl<'a, B: IntoByteSlice<'a>, T: ?Sized> Ref<B, T> { 134 /// Access the byte slice as an [`IntoByteSlice`]. 135 /// 136 /// # Safety 137 /// 138 /// The caller promises not to call methods on the returned 139 /// [`IntoByteSlice`] other than `IntoByteSlice` methods (for example, 140 /// via `Any::downcast_ref`). 141 /// 142 /// `as_byte_slice` promises to return a `ByteSlice` whose referent is 143 /// validly-aligned for `T` and has a valid size for `T`. 144 pub(crate) unsafe fn into_byte_slice(self) -> impl IntoByteSlice<'a> { 145 // INVARIANTS: The caller promises not to call methods other than 146 // those on `IntoByteSlice`. Since `B: ByteSlice`, dereference 147 // stability guarantees that calling `ByteSlice` methods will not 148 // change the address or length of `self.0`'s referent. 149 // 150 // SAFETY: By invariant on `self.0`, the alignment and size 151 // post-conditions are upheld. 152 self.0 153 } 154 } 155 156 impl<'a, B: IntoByteSliceMut<'a>, T: ?Sized> Ref<B, T> { 157 /// Access the byte slice as an [`IntoByteSliceMut`]. 158 /// 159 /// # Safety 160 /// 161 /// The caller promises not to call methods on the returned 162 /// [`IntoByteSliceMut`] other than `IntoByteSliceMut` methods (for 163 /// example, via `Any::downcast_mut`). 164 /// 165 /// `as_byte_slice` promises to return a `ByteSlice` whose referent is 166 /// validly-aligned for `T` and has a valid size for `T`. 167 pub(crate) unsafe fn into_byte_slice_mut(self) -> impl IntoByteSliceMut<'a> { 168 // INVARIANTS: The caller promises not to call methods other than 169 // those on `IntoByteSliceMut`. Since `B: ByteSlice`, dereference 170 // stability guarantees that calling `ByteSlice` methods will not 171 // change the address or length of `self.0`'s referent. 172 // 173 // SAFETY: By invariant on `self.0`, the alignment and size 174 // post-conditions are upheld. 175 self.0 176 } 177 } 178 179 impl<B: CloneableByteSlice + Clone, T: ?Sized> Clone for Ref<B, T> { 180 #[inline] 181 fn clone(&self) -> Ref<B, T> { 182 // INVARIANTS: Since `B: CloneableByteSlice`, `self.0.clone()` has 183 // the same address and length as `self.0`. Since `self.0` upholds 184 // the field invariants, so does `self.0.clone()`. 185 Ref(self.0.clone(), PhantomData) 186 } 187 } 188 189 // INVARIANTS: Since `B: CopyableByteSlice`, the copied `Ref`'s `.0` has the 190 // same address and length as the original `Ref`'s `.0`. Since the original 191 // upholds the field invariants, so does the copy. 192 impl<B: CopyableByteSlice + Copy, T: ?Sized> Copy for Ref<B, T> {} 193 } 194 195 #[allow(unreachable_pub)] // This is a false positive on our MSRV toolchain. 196 pub use def::Ref; 197 198 use crate::pointer::{ 199 invariant::{Aligned, BecauseExclusive, Initialized, Unaligned, Valid}, 200 BecauseRead, PtrInner, 201 }; 202 203 impl<B, T> Ref<B, T> 204 where 205 B: ByteSlice, 206 { 207 #[must_use = "has no side effects"] 208 pub(crate) fn sized_from(bytes: B) -> Result<Ref<B, T>, CastError<B, T>> { 209 if bytes.len() != mem::size_of::<T>() { 210 return Err(SizeError::new(bytes).into()); 211 } 212 if let Err(err) = util::validate_aligned_to::<_, T>(bytes.deref()) { 213 return Err(err.with_src(bytes).into()); 214 } 215 216 // SAFETY: We just validated size and alignment. 217 Ok(unsafe { Ref::new_unchecked(bytes) }) 218 } 219 } 220 221 impl<B, T> Ref<B, T> 222 where 223 B: SplitByteSlice, 224 { 225 #[must_use = "has no side effects"] 226 pub(crate) fn sized_from_prefix(bytes: B) -> Result<(Ref<B, T>, B), CastError<B, T>> { 227 if bytes.len() < mem::size_of::<T>() { 228 return Err(SizeError::new(bytes).into()); 229 } 230 if let Err(err) = util::validate_aligned_to::<_, T>(bytes.deref()) { 231 return Err(err.with_src(bytes).into()); 232 } 233 let (bytes, suffix) = bytes.split_at(mem::size_of::<T>()).map_err( 234 #[inline(always)] 235 |b| SizeError::new(b).into(), 236 )?; 237 // SAFETY: We just validated alignment and that `bytes` is at least as 238 // large as `T`. `bytes.split_at(mem::size_of::<T>())?` ensures that the 239 // new `bytes` is exactly the size of `T`. By safety postcondition on 240 // `SplitByteSlice::split_at` we can rely on `split_at` to produce the 241 // correct `bytes` and `suffix`. 242 let r = unsafe { Ref::new_unchecked(bytes) }; 243 Ok((r, suffix)) 244 } 245 246 #[must_use = "has no side effects"] 247 pub(crate) fn sized_from_suffix(bytes: B) -> Result<(B, Ref<B, T>), CastError<B, T>> { 248 let bytes_len = bytes.len(); 249 let split_at = if let Some(split_at) = bytes_len.checked_sub(mem::size_of::<T>()) { 250 split_at 251 } else { 252 return Err(SizeError::new(bytes).into()); 253 }; 254 let (prefix, bytes) = bytes.split_at(split_at).map_err(|b| SizeError::new(b).into())?; 255 if let Err(err) = util::validate_aligned_to::<_, T>(bytes.deref()) { 256 return Err(err.with_src(bytes).into()); 257 } 258 // SAFETY: Since `split_at` is defined as `bytes_len - size_of::<T>()`, 259 // the `bytes` which results from `let (prefix, bytes) = 260 // bytes.split_at(split_at)?` has length `size_of::<T>()`. After 261 // constructing `bytes`, we validate that it has the proper alignment. 262 // By safety postcondition on `SplitByteSlice::split_at` we can rely on 263 // `split_at` to produce the correct `prefix` and `bytes`. 264 let r = unsafe { Ref::new_unchecked(bytes) }; 265 Ok((prefix, r)) 266 } 267 } 268 269 impl<B, T> Ref<B, T> 270 where 271 B: ByteSlice, 272 T: KnownLayout + Immutable + ?Sized, 273 { 274 /// Constructs a `Ref` from a byte slice. 275 /// 276 /// If the length of `source` is not a [valid size of `T`][valid-size], or 277 /// if `source` is not appropriately aligned for `T`, this returns `Err`. If 278 /// [`T: Unaligned`][t-unaligned], you can [infallibly discard the alignment 279 /// error][size-error-from]. 280 /// 281 /// `T` may be a sized type, a slice, or a [slice DST][slice-dst]. 282 /// 283 /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 284 /// [t-unaligned]: crate::Unaligned 285 /// [size-error-from]: error/struct.SizeError.html#method.from-1 286 /// [slice-dst]: KnownLayout#dynamically-sized-types 287 /// 288 /// # Compile-Time Assertions 289 /// 290 /// This method cannot yet be used on unsized types whose dynamically-sized 291 /// component is zero-sized. Attempting to use this method on such types 292 /// results in a compile-time assertion error; e.g.: 293 /// 294 /// ```compile_fail,E0080 295 /// use zerocopy::*; 296 /// # use zerocopy_derive::*; 297 /// 298 /// #[derive(Immutable, KnownLayout)] 299 /// #[repr(C)] 300 /// struct ZSTy { 301 /// leading_sized: u16, 302 /// trailing_dst: [()], 303 /// } 304 /// 305 /// let _ = Ref::<_, ZSTy>::from_bytes(&b"UU"[..]); // ⚠ Compile Error! 306 /// ``` 307 #[must_use = "has no side effects"] 308 #[inline] 309 pub fn from_bytes(source: B) -> Result<Ref<B, T>, CastError<B, T>> { 310 static_assert_dst_is_not_zst!(T); 311 if let Err(e) = 312 Ptr::from_ref(source.deref()).try_cast_into_no_leftover::<T, BecauseImmutable>(None) 313 { 314 return Err(e.with_src(()).with_src(source)); 315 } 316 // SAFETY: `try_cast_into_no_leftover` validates size and alignment. 317 Ok(unsafe { Ref::new_unchecked(source) }) 318 } 319 } 320 321 impl<B, T> Ref<B, T> 322 where 323 B: SplitByteSlice, 324 T: KnownLayout + Immutable + ?Sized, 325 { 326 /// Constructs a `Ref` from the prefix of a byte slice. 327 /// 328 /// This method computes the [largest possible size of `T`][valid-size] that 329 /// can fit in the leading bytes of `source`, then attempts to return both a 330 /// `Ref` to those bytes, and a reference to the remaining bytes. If there 331 /// are insufficient bytes, or if `source` is not appropriately aligned, 332 /// this returns `Err`. If [`T: Unaligned`][t-unaligned], you can 333 /// [infallibly discard the alignment error][size-error-from]. 334 /// 335 /// `T` may be a sized type, a slice, or a [slice DST][slice-dst]. 336 /// 337 /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 338 /// [t-unaligned]: crate::Unaligned 339 /// [size-error-from]: error/struct.SizeError.html#method.from-1 340 /// [slice-dst]: KnownLayout#dynamically-sized-types 341 /// 342 /// # Compile-Time Assertions 343 /// 344 /// This method cannot yet be used on unsized types whose dynamically-sized 345 /// component is zero-sized. Attempting to use this method on such types 346 /// results in a compile-time assertion error; e.g.: 347 /// 348 /// ```compile_fail,E0080 349 /// use zerocopy::*; 350 /// # use zerocopy_derive::*; 351 /// 352 /// #[derive(Immutable, KnownLayout)] 353 /// #[repr(C)] 354 /// struct ZSTy { 355 /// leading_sized: u16, 356 /// trailing_dst: [()], 357 /// } 358 /// 359 /// let _ = Ref::<_, ZSTy>::from_prefix(&b"UU"[..]); // ⚠ Compile Error! 360 /// ``` 361 #[must_use = "has no side effects"] 362 #[inline] 363 pub fn from_prefix(source: B) -> Result<(Ref<B, T>, B), CastError<B, T>> { 364 static_assert_dst_is_not_zst!(T); 365 let remainder = match Ptr::from_ref(source.deref()) 366 .try_cast_into::<T, BecauseImmutable>(CastType::Prefix, None) 367 { 368 Ok((_, remainder)) => remainder, 369 Err(e) => { 370 return Err(e.with_src(()).with_src(source)); 371 } 372 }; 373 374 // SAFETY: `remainder` is constructed as a subset of `source`, and so it 375 // cannot have a larger size than `source`. Both of their `len` methods 376 // measure bytes (`source` deref's to `[u8]`, and `remainder` is a 377 // `Ptr<[u8]>`), so `source.len() >= remainder.len()`. Thus, this cannot 378 // underflow. 379 #[allow(unstable_name_collisions)] 380 let split_at = unsafe { source.len().unchecked_sub(remainder.len()) }; 381 let (bytes, suffix) = source.split_at(split_at).map_err(|b| SizeError::new(b).into())?; 382 // SAFETY: `try_cast_into` validates size and alignment, and returns a 383 // `split_at` that indicates how many bytes of `source` correspond to a 384 // valid `T`. By safety postcondition on `SplitByteSlice::split_at` we 385 // can rely on `split_at` to produce the correct `source` and `suffix`. 386 let r = unsafe { Ref::new_unchecked(bytes) }; 387 Ok((r, suffix)) 388 } 389 390 /// Constructs a `Ref` from the suffix of a byte slice. 391 /// 392 /// This method computes the [largest possible size of `T`][valid-size] that 393 /// can fit in the trailing bytes of `source`, then attempts to return both 394 /// a `Ref` to those bytes, and a reference to the preceding bytes. If there 395 /// are insufficient bytes, or if that suffix of `source` is not 396 /// appropriately aligned, this returns `Err`. If [`T: 397 /// Unaligned`][t-unaligned], you can [infallibly discard the alignment 398 /// error][size-error-from]. 399 /// 400 /// `T` may be a sized type, a slice, or a [slice DST][slice-dst]. 401 /// 402 /// [valid-size]: crate::KnownLayout#what-is-a-valid-size 403 /// [t-unaligned]: crate::Unaligned 404 /// [size-error-from]: error/struct.SizeError.html#method.from-1 405 /// [slice-dst]: KnownLayout#dynamically-sized-types 406 /// 407 /// # Compile-Time Assertions 408 /// 409 /// This method cannot yet be used on unsized types whose dynamically-sized 410 /// component is zero-sized. Attempting to use this method on such types 411 /// results in a compile-time assertion error; e.g.: 412 /// 413 /// ```compile_fail,E0080 414 /// use zerocopy::*; 415 /// # use zerocopy_derive::*; 416 /// 417 /// #[derive(Immutable, KnownLayout)] 418 /// #[repr(C)] 419 /// struct ZSTy { 420 /// leading_sized: u16, 421 /// trailing_dst: [()], 422 /// } 423 /// 424 /// let _ = Ref::<_, ZSTy>::from_suffix(&b"UU"[..]); // ⚠ Compile Error! 425 /// ``` 426 #[must_use = "has no side effects"] 427 #[inline] 428 pub fn from_suffix(source: B) -> Result<(B, Ref<B, T>), CastError<B, T>> { 429 static_assert_dst_is_not_zst!(T); 430 let remainder = match Ptr::from_ref(source.deref()) 431 .try_cast_into::<T, BecauseImmutable>(CastType::Suffix, None) 432 { 433 Ok((_, remainder)) => remainder, 434 Err(e) => { 435 let e = e.with_src(()); 436 return Err(e.with_src(source)); 437 } 438 }; 439 440 let split_at = remainder.len(); 441 let (prefix, bytes) = source.split_at(split_at).map_err(|b| SizeError::new(b).into())?; 442 // SAFETY: `try_cast_into` validates size and alignment, and returns a 443 // `split_at` that indicates how many bytes of `source` correspond to a 444 // valid `T`. By safety postcondition on `SplitByteSlice::split_at` we 445 // can rely on `split_at` to produce the correct `prefix` and `bytes`. 446 let r = unsafe { Ref::new_unchecked(bytes) }; 447 Ok((prefix, r)) 448 } 449 } 450 451 impl<B, T> Ref<B, T> 452 where 453 B: ByteSlice, 454 T: KnownLayout<PointerMetadata = usize> + Immutable + ?Sized, 455 { 456 /// Constructs a `Ref` from the given bytes with DST length equal to `count` 457 /// without copying. 458 /// 459 /// This method attempts to return a `Ref` to the prefix of `source` 460 /// interpreted as a `T` with `count` trailing elements, and a reference to 461 /// the remaining bytes. If the length of `source` is not equal to the size 462 /// of `Self` with `count` elements, or if `source` is not appropriately 463 /// aligned, this returns `Err`. If [`T: Unaligned`][t-unaligned], you can 464 /// [infallibly discard the alignment error][size-error-from]. 465 /// 466 /// [t-unaligned]: crate::Unaligned 467 /// [size-error-from]: error/struct.SizeError.html#method.from-1 468 /// 469 /// # Compile-Time Assertions 470 /// 471 /// This method cannot yet be used on unsized types whose dynamically-sized 472 /// component is zero-sized. Attempting to use this method on such types 473 /// results in a compile-time assertion error; e.g.: 474 /// 475 /// ```compile_fail,E0080 476 /// use zerocopy::*; 477 /// # use zerocopy_derive::*; 478 /// 479 /// #[derive(Immutable, KnownLayout)] 480 /// #[repr(C)] 481 /// struct ZSTy { 482 /// leading_sized: u16, 483 /// trailing_dst: [()], 484 /// } 485 /// 486 /// let _ = Ref::<_, ZSTy>::from_bytes_with_elems(&b"UU"[..], 42); // ⚠ Compile Error! 487 /// ``` 488 #[inline] 489 pub fn from_bytes_with_elems(source: B, count: usize) -> Result<Ref<B, T>, CastError<B, T>> { 490 static_assert_dst_is_not_zst!(T); 491 let expected_len = match T::size_for_metadata(count) { 492 Some(len) => len, 493 None => return Err(SizeError::new(source).into()), 494 }; 495 if source.len() != expected_len { 496 return Err(SizeError::new(source).into()); 497 } 498 Self::from_bytes(source) 499 } 500 } 501 502 impl<B, T> Ref<B, T> 503 where 504 B: SplitByteSlice, 505 T: KnownLayout<PointerMetadata = usize> + Immutable + ?Sized, 506 { 507 /// Constructs a `Ref` from the prefix of the given bytes with DST 508 /// length equal to `count` without copying. 509 /// 510 /// This method attempts to return a `Ref` to the prefix of `source` 511 /// interpreted as a `T` with `count` trailing elements, and a reference to 512 /// the remaining bytes. If there are insufficient bytes, or if `source` is 513 /// not appropriately aligned, this returns `Err`. If [`T: 514 /// Unaligned`][t-unaligned], you can [infallibly discard the alignment 515 /// error][size-error-from]. 516 /// 517 /// [t-unaligned]: crate::Unaligned 518 /// [size-error-from]: error/struct.SizeError.html#method.from-1 519 /// 520 /// # Compile-Time Assertions 521 /// 522 /// This method cannot yet be used on unsized types whose dynamically-sized 523 /// component is zero-sized. Attempting to use this method on such types 524 /// results in a compile-time assertion error; e.g.: 525 /// 526 /// ```compile_fail,E0080 527 /// use zerocopy::*; 528 /// # use zerocopy_derive::*; 529 /// 530 /// #[derive(Immutable, KnownLayout)] 531 /// #[repr(C)] 532 /// struct ZSTy { 533 /// leading_sized: u16, 534 /// trailing_dst: [()], 535 /// } 536 /// 537 /// let _ = Ref::<_, ZSTy>::from_prefix_with_elems(&b"UU"[..], 42); // ⚠ Compile Error! 538 /// ``` 539 #[inline] 540 pub fn from_prefix_with_elems( 541 source: B, 542 count: usize, 543 ) -> Result<(Ref<B, T>, B), CastError<B, T>> { 544 static_assert_dst_is_not_zst!(T); 545 let expected_len = match T::size_for_metadata(count) { 546 Some(len) => len, 547 None => return Err(SizeError::new(source).into()), 548 }; 549 let (prefix, bytes) = source.split_at(expected_len).map_err(SizeError::new)?; 550 Self::from_bytes(prefix).map(move |l| (l, bytes)) 551 } 552 553 /// Constructs a `Ref` from the suffix of the given bytes with DST length 554 /// equal to `count` without copying. 555 /// 556 /// This method attempts to return a `Ref` to the suffix of `source` 557 /// interpreted as a `T` with `count` trailing elements, and a reference to 558 /// the preceding bytes. If there are insufficient bytes, or if that suffix 559 /// of `source` is not appropriately aligned, this returns `Err`. If [`T: 560 /// Unaligned`][t-unaligned], you can [infallibly discard the alignment 561 /// error][size-error-from]. 562 /// 563 /// [t-unaligned]: crate::Unaligned 564 /// [size-error-from]: error/struct.SizeError.html#method.from-1 565 /// 566 /// # Compile-Time Assertions 567 /// 568 /// This method cannot yet be used on unsized types whose dynamically-sized 569 /// component is zero-sized. Attempting to use this method on such types 570 /// results in a compile-time assertion error; e.g.: 571 /// 572 /// ```compile_fail,E0080 573 /// use zerocopy::*; 574 /// # use zerocopy_derive::*; 575 /// 576 /// #[derive(Immutable, KnownLayout)] 577 /// #[repr(C)] 578 /// struct ZSTy { 579 /// leading_sized: u16, 580 /// trailing_dst: [()], 581 /// } 582 /// 583 /// let _ = Ref::<_, ZSTy>::from_suffix_with_elems(&b"UU"[..], 42); // ⚠ Compile Error! 584 /// ``` 585 #[inline] 586 pub fn from_suffix_with_elems( 587 source: B, 588 count: usize, 589 ) -> Result<(B, Ref<B, T>), CastError<B, T>> { 590 static_assert_dst_is_not_zst!(T); 591 let expected_len = match T::size_for_metadata(count) { 592 Some(len) => len, 593 None => return Err(SizeError::new(source).into()), 594 }; 595 let split_at = if let Some(split_at) = source.len().checked_sub(expected_len) { 596 split_at 597 } else { 598 return Err(SizeError::new(source).into()); 599 }; 600 // SAFETY: The preceding `source.len().checked_sub(expected_len)` 601 // guarantees that `split_at` is in-bounds. 602 let (bytes, suffix) = unsafe { source.split_at_unchecked(split_at) }; 603 Self::from_bytes(suffix).map(move |l| (bytes, l)) 604 } 605 } 606 607 impl<'a, B, T> Ref<B, T> 608 where 609 B: 'a + IntoByteSlice<'a>, 610 T: FromBytes + KnownLayout + Immutable + ?Sized, 611 { 612 /// Converts this `Ref` into a reference. 613 /// 614 /// `into_ref` consumes the `Ref`, and returns a reference to `T`. 615 /// 616 /// Note: this is an associated function, which means that you have to call 617 /// it as `Ref::into_ref(r)` instead of `r.into_ref()`. This is so that 618 /// there is no conflict with a method on the inner type. 619 #[must_use = "has no side effects"] 620 #[inline(always)] 621 pub fn into_ref(r: Self) -> &'a T { 622 // Presumably unreachable, since we've guarded each constructor of `Ref`. 623 static_assert_dst_is_not_zst!(T); 624 625 // SAFETY: We don't call any methods on `b` other than those provided by 626 // `IntoByteSlice`. 627 let b = unsafe { r.into_byte_slice() }; 628 let b = b.into_byte_slice(); 629 630 if let crate::layout::SizeInfo::Sized { .. } = T::LAYOUT.size_info { 631 let ptr = Ptr::from_ref(b); 632 // SAFETY: We just checked that `T: Sized`. By invariant on `r`, 633 // `b`'s size is equal to `size_of::<T>()`. 634 let ptr = unsafe { cast_for_sized::<T, _, _, _>(ptr) }; 635 636 // SAFETY: None of the preceding transformations modifies the 637 // address of the pointer, and by invariant on `r`, we know that it 638 // is validly-aligned. 639 let ptr = unsafe { ptr.assume_alignment::<Aligned>() }; 640 return ptr.as_ref(); 641 } 642 643 // PANICS: By post-condition on `into_byte_slice`, `b`'s size and 644 // alignment are valid for `T`. By post-condition, `b.into_byte_slice()` 645 // produces a byte slice with identical address and length to that 646 // produced by `b.deref()`. 647 let ptr = Ptr::from_ref(b.into_byte_slice()) 648 .try_cast_into_no_leftover::<T, BecauseImmutable>(None) 649 .expect("zerocopy internal error: into_ref should be infallible"); 650 let ptr = ptr.recall_validity(); 651 ptr.as_ref() 652 } 653 } 654 655 impl<'a, B, T> Ref<B, T> 656 where 657 B: 'a + IntoByteSliceMut<'a>, 658 T: FromBytes + IntoBytes + KnownLayout + ?Sized, 659 { 660 /// Converts this `Ref` into a mutable reference. 661 /// 662 /// `into_mut` consumes the `Ref`, and returns a mutable reference to `T`. 663 /// 664 /// Note: this is an associated function, which means that you have to call 665 /// it as `Ref::into_mut(r)` instead of `r.into_mut()`. This is so that 666 /// there is no conflict with a method on the inner type. 667 #[must_use = "has no side effects"] 668 #[inline(always)] 669 pub fn into_mut(r: Self) -> &'a mut T { 670 // Presumably unreachable, since we've guarded each constructor of `Ref`. 671 static_assert_dst_is_not_zst!(T); 672 673 // SAFETY: We don't call any methods on `b` other than those provided by 674 // `IntoByteSliceMut`. 675 let b = unsafe { r.into_byte_slice_mut() }; 676 let b = b.into_byte_slice_mut(); 677 678 if let crate::layout::SizeInfo::Sized { .. } = T::LAYOUT.size_info { 679 let ptr = Ptr::from_mut(b); 680 // SAFETY: We just checked that `T: Sized`. By invariant on `r`, 681 // `b`'s size is equal to `size_of::<T>()`. 682 let ptr = unsafe { 683 cast_for_sized::< 684 T, 685 _, 686 (BecauseRead, BecauseExclusive), 687 (BecauseMutationCompatible, BecauseInvariantsEq), 688 >(ptr) 689 }; 690 691 // SAFETY: None of the preceding transformations modifies the 692 // address of the pointer, and by invariant on `r`, we know that it 693 // is validly-aligned. 694 let ptr = unsafe { ptr.assume_alignment::<Aligned>() }; 695 return ptr.as_mut(); 696 } 697 698 // PANICS: By post-condition on `into_byte_slice_mut`, `b`'s size and 699 // alignment are valid for `T`. By post-condition, 700 // `b.into_byte_slice_mut()` produces a byte slice with identical 701 // address and length to that produced by `b.deref_mut()`. 702 let ptr = Ptr::from_mut(b.into_byte_slice_mut()) 703 .try_cast_into_no_leftover::<T, BecauseExclusive>(None) 704 .expect("zerocopy internal error: into_ref should be infallible"); 705 let ptr = ptr.recall_validity::<_, (_, (_, _))>(); 706 ptr.as_mut() 707 } 708 } 709 710 impl<B, T> Ref<B, T> 711 where 712 B: ByteSlice, 713 T: ?Sized, 714 { 715 /// Gets the underlying bytes. 716 /// 717 /// Note: this is an associated function, which means that you have to call 718 /// it as `Ref::bytes(r)` instead of `r.bytes()`. This is so that there is 719 /// no conflict with a method on the inner type. 720 #[inline] 721 pub fn bytes(r: &Self) -> &[u8] { 722 // SAFETY: We don't call any methods on `b` other than those provided by 723 // `ByteSlice`. 724 unsafe { r.as_byte_slice().deref() } 725 } 726 } 727 728 impl<B, T> Ref<B, T> 729 where 730 B: ByteSliceMut, 731 T: ?Sized, 732 { 733 /// Gets the underlying bytes mutably. 734 /// 735 /// Note: this is an associated function, which means that you have to call 736 /// it as `Ref::bytes_mut(r)` instead of `r.bytes_mut()`. This is so that 737 /// there is no conflict with a method on the inner type. 738 #[inline] 739 pub fn bytes_mut(r: &mut Self) -> &mut [u8] { 740 // SAFETY: We don't call any methods on `b` other than those provided by 741 // `ByteSliceMut`. 742 unsafe { r.as_byte_slice_mut().deref_mut() } 743 } 744 } 745 746 impl<B, T> Ref<B, T> 747 where 748 B: ByteSlice, 749 T: FromBytes, 750 { 751 /// Reads a copy of `T`. 752 /// 753 /// Note: this is an associated function, which means that you have to call 754 /// it as `Ref::read(r)` instead of `r.read()`. This is so that there is no 755 /// conflict with a method on the inner type. 756 #[must_use = "has no side effects"] 757 #[inline] 758 pub fn read(r: &Self) -> T { 759 // SAFETY: We don't call any methods on `b` other than those provided by 760 // `ByteSlice`. 761 let b = unsafe { r.as_byte_slice() }; 762 763 // SAFETY: By postcondition on `as_byte_slice`, we know that `b` is a 764 // valid size and alignment for `T`. By safety invariant on `ByteSlice`, 765 // we know that this is preserved via `.deref()`. Because `T: 766 // FromBytes`, it is sound to interpret these bytes as a `T`. 767 unsafe { ptr::read(b.deref().as_ptr().cast::<T>()) } 768 } 769 } 770 771 impl<B, T> Ref<B, T> 772 where 773 B: ByteSliceMut, 774 T: IntoBytes, 775 { 776 /// Writes the bytes of `t` and then forgets `t`. 777 /// 778 /// Note: this is an associated function, which means that you have to call 779 /// it as `Ref::write(r, t)` instead of `r.write(t)`. This is so that there 780 /// is no conflict with a method on the inner type. 781 #[inline] 782 pub fn write(r: &mut Self, t: T) { 783 // SAFETY: We don't call any methods on `b` other than those provided by 784 // `ByteSliceMut`. 785 let b = unsafe { r.as_byte_slice_mut() }; 786 787 // SAFETY: By postcondition on `as_byte_slice_mut`, we know that `b` is 788 // a valid size and alignment for `T`. By safety invariant on 789 // `ByteSlice`, we know that this is preserved via `.deref()`. Writing 790 // `t` to the buffer will allow all of the bytes of `t` to be accessed 791 // as a `[u8]`, but because `T: IntoBytes`, we know that this is sound. 792 unsafe { ptr::write(b.deref_mut().as_mut_ptr().cast::<T>(), t) } 793 } 794 } 795 796 impl<B, T> Deref for Ref<B, T> 797 where 798 B: ByteSlice, 799 T: FromBytes + KnownLayout + Immutable + ?Sized, 800 { 801 type Target = T; 802 #[inline] 803 fn deref(&self) -> &T { 804 // Presumably unreachable, since we've guarded each constructor of `Ref`. 805 static_assert_dst_is_not_zst!(T); 806 807 // SAFETY: We don't call any methods on `b` other than those provided by 808 // `ByteSlice`. 809 let b = unsafe { self.as_byte_slice() }; 810 let b = b.deref(); 811 812 if let crate::layout::SizeInfo::Sized { .. } = T::LAYOUT.size_info { 813 let ptr = Ptr::from_ref(b); 814 // SAFETY: We just checked that `T: Sized`. By invariant on `r`, 815 // `b`'s size is equal to `size_of::<T>()`. 816 let ptr = unsafe { cast_for_sized::<T, _, _, _>(ptr) }; 817 818 // SAFETY: None of the preceding transformations modifies the 819 // address of the pointer, and by invariant on `r`, we know that it 820 // is validly-aligned. 821 let ptr = unsafe { ptr.assume_alignment::<Aligned>() }; 822 return ptr.as_ref(); 823 } 824 825 // PANICS: By postcondition on `as_byte_slice`, `b`'s size and alignment 826 // are valid for `T`, and by invariant on `ByteSlice`, these are 827 // preserved through `.deref()`, so this `unwrap` will not panic. 828 let ptr = Ptr::from_ref(b) 829 .try_cast_into_no_leftover::<T, BecauseImmutable>(None) 830 .expect("zerocopy internal error: Deref::deref should be infallible"); 831 let ptr = ptr.recall_validity(); 832 ptr.as_ref() 833 } 834 } 835 836 impl<B, T> DerefMut for Ref<B, T> 837 where 838 B: ByteSliceMut, 839 // FIXME(#251): We can't remove `Immutable` here because it's required by 840 // the impl of `Deref`, which is a super-trait of `DerefMut`. Maybe we can 841 // add a separate inherent method for this? 842 T: FromBytes + IntoBytes + KnownLayout + Immutable + ?Sized, 843 { 844 #[inline] 845 fn deref_mut(&mut self) -> &mut T { 846 // Presumably unreachable, since we've guarded each constructor of `Ref`. 847 static_assert_dst_is_not_zst!(T); 848 849 // SAFETY: We don't call any methods on `b` other than those provided by 850 // `ByteSliceMut`. 851 let b = unsafe { self.as_byte_slice_mut() }; 852 let b = b.deref_mut(); 853 854 if let crate::layout::SizeInfo::Sized { .. } = T::LAYOUT.size_info { 855 let ptr = Ptr::from_mut(b); 856 // SAFETY: We just checked that `T: Sized`. By invariant on `r`, 857 // `b`'s size is equal to `size_of::<T>()`. 858 let ptr = unsafe { 859 cast_for_sized::< 860 T, 861 _, 862 (BecauseRead, BecauseExclusive), 863 (BecauseMutationCompatible, BecauseInvariantsEq), 864 >(ptr) 865 }; 866 867 // SAFETY: None of the preceding transformations modifies the 868 // address of the pointer, and by invariant on `r`, we know that it 869 // is validly-aligned. 870 let ptr = unsafe { ptr.assume_alignment::<Aligned>() }; 871 return ptr.as_mut(); 872 } 873 874 // PANICS: By postcondition on `as_byte_slice_mut`, `b`'s size and 875 // alignment are valid for `T`, and by invariant on `ByteSlice`, these 876 // are preserved through `.deref_mut()`, so this `unwrap` will not 877 // panic. 878 let ptr = Ptr::from_mut(b) 879 .try_cast_into_no_leftover::<T, BecauseExclusive>(None) 880 .expect("zerocopy internal error: DerefMut::deref_mut should be infallible"); 881 let ptr = ptr.recall_validity::<_, (_, (_, BecauseExclusive))>(); 882 ptr.as_mut() 883 } 884 } 885 886 impl<T, B> Display for Ref<B, T> 887 where 888 B: ByteSlice, 889 T: FromBytes + Display + KnownLayout + Immutable + ?Sized, 890 { 891 #[inline] 892 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 893 let inner: &T = self; 894 inner.fmt(fmt) 895 } 896 } 897 898 impl<T, B> Debug for Ref<B, T> 899 where 900 B: ByteSlice, 901 T: FromBytes + Debug + KnownLayout + Immutable + ?Sized, 902 { 903 #[inline] 904 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 905 let inner: &T = self; 906 fmt.debug_tuple("Ref").field(&inner).finish() 907 } 908 } 909 910 impl<T, B> Eq for Ref<B, T> 911 where 912 B: ByteSlice, 913 T: FromBytes + Eq + KnownLayout + Immutable + ?Sized, 914 { 915 } 916 917 impl<T, B> PartialEq for Ref<B, T> 918 where 919 B: ByteSlice, 920 T: FromBytes + PartialEq + KnownLayout + Immutable + ?Sized, 921 { 922 #[inline] 923 fn eq(&self, other: &Self) -> bool { 924 self.deref().eq(other.deref()) 925 } 926 } 927 928 impl<T, B> Ord for Ref<B, T> 929 where 930 B: ByteSlice, 931 T: FromBytes + Ord + KnownLayout + Immutable + ?Sized, 932 { 933 #[inline] 934 fn cmp(&self, other: &Self) -> Ordering { 935 let inner: &T = self; 936 let other_inner: &T = other; 937 inner.cmp(other_inner) 938 } 939 } 940 941 impl<T, B> PartialOrd for Ref<B, T> 942 where 943 B: ByteSlice, 944 T: FromBytes + PartialOrd + KnownLayout + Immutable + ?Sized, 945 { 946 #[inline] 947 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 948 let inner: &T = self; 949 let other_inner: &T = other; 950 inner.partial_cmp(other_inner) 951 } 952 } 953 954 /// # Safety 955 /// 956 /// `T: Sized` and `ptr`'s referent must have size `size_of::<T>()`. 957 #[inline(always)] 958 unsafe fn cast_for_sized<'a, T, A, R, S>( 959 ptr: Ptr<'a, [u8], (A, Aligned, Valid)>, 960 ) -> Ptr<'a, T, (A, Unaligned, Valid)> 961 where 962 T: FromBytes + KnownLayout + ?Sized, 963 A: crate::invariant::Aliasing, 964 [u8]: MutationCompatible<T, A, Initialized, Initialized, R>, 965 T: TransmuteFromPtr<T, A, Initialized, Valid, crate::pointer::cast::IdCast, S>, 966 { 967 use crate::pointer::cast::{Cast, Project}; 968 969 enum CastForSized {} 970 971 // SAFETY: `CastForSized` is only used below with the input `ptr`, which the 972 // caller promises has size `size_of::<T>()`. Thus, the referent produced in 973 // this cast has the same size as `ptr`'s referent. All operations preserve 974 // provenance. 975 unsafe impl<T: ?Sized + KnownLayout> Project<[u8], T> for CastForSized { 976 #[inline(always)] 977 fn project(src: PtrInner<'_, [u8]>) -> *mut T { 978 T::raw_from_ptr_len( 979 src.as_non_null().cast(), 980 <T::PointerMetadata as crate::PointerMetadata>::from_elem_count(0), 981 ) 982 .as_ptr() 983 } 984 } 985 986 // SAFETY: The `Project::project` impl preserves referent address. 987 unsafe impl<T: ?Sized + KnownLayout> Cast<[u8], T> for CastForSized {} 988 989 ptr.recall_validity::<Initialized, (_, (_, _))>() 990 .cast::<_, CastForSized, _>() 991 .recall_validity::<Valid, _>() 992 } 993 994 #[cfg(test)] 995 #[allow(clippy::assertions_on_result_states)] 996 mod tests { 997 use core::convert::TryInto as _; 998 999 use super::*; 1000 use crate::util::testutil::*; 1001 1002 #[test] 1003 fn test_mut_slice_into_ref() { 1004 // Prior to #1260/#1299, calling `into_ref` on a `&mut [u8]`-backed 1005 // `Ref` was not supported. 1006 let mut buf = [0u8]; 1007 let r = Ref::<&mut [u8], u8>::from_bytes(&mut buf).unwrap(); 1008 assert_eq!(Ref::into_ref(r), &0); 1009 } 1010 1011 #[test] 1012 fn test_address() { 1013 // Test that the `Deref` and `DerefMut` implementations return a 1014 // reference which points to the right region of memory. 1015 1016 let buf = [0]; 1017 let r = Ref::<_, u8>::from_bytes(&buf[..]).unwrap(); 1018 let buf_ptr = buf.as_ptr(); 1019 let deref_ptr: *const u8 = r.deref(); 1020 assert_eq!(buf_ptr, deref_ptr); 1021 1022 let buf = [0]; 1023 let r = Ref::<_, [u8]>::from_bytes(&buf[..]).unwrap(); 1024 let buf_ptr = buf.as_ptr(); 1025 let deref_ptr = r.deref().as_ptr(); 1026 assert_eq!(buf_ptr, deref_ptr); 1027 } 1028 1029 // Verify that values written to a `Ref` are properly shared between the 1030 // typed and untyped representations, that reads via `deref` and `read` 1031 // behave the same, and that writes via `deref_mut` and `write` behave the 1032 // same. 1033 fn test_new_helper(mut r: Ref<&mut [u8], AU64>) { 1034 // assert that the value starts at 0 1035 assert_eq!(*r, AU64(0)); 1036 assert_eq!(Ref::read(&r), AU64(0)); 1037 1038 // Assert that values written to the typed value are reflected in the 1039 // byte slice. 1040 const VAL1: AU64 = AU64(0xFF00FF00FF00FF00); 1041 *r = VAL1; 1042 assert_eq!(Ref::bytes(&r), &VAL1.to_bytes()); 1043 *r = AU64(0); 1044 Ref::write(&mut r, VAL1); 1045 assert_eq!(Ref::bytes(&r), &VAL1.to_bytes()); 1046 1047 // Assert that values written to the byte slice are reflected in the 1048 // typed value. 1049 const VAL2: AU64 = AU64(!VAL1.0); // different from `VAL1` 1050 Ref::bytes_mut(&mut r).copy_from_slice(&VAL2.to_bytes()[..]); 1051 assert_eq!(*r, VAL2); 1052 assert_eq!(Ref::read(&r), VAL2); 1053 } 1054 1055 // Verify that values written to a `Ref` are properly shared between the 1056 // typed and untyped representations; pass a value with `typed_len` `AU64`s 1057 // backed by an array of `typed_len * 8` bytes. 1058 fn test_new_helper_slice(mut r: Ref<&mut [u8], [AU64]>, typed_len: usize) { 1059 // Assert that the value starts out zeroed. 1060 assert_eq!(&*r, vec![AU64(0); typed_len].as_slice()); 1061 1062 // Check the backing storage is the exact same slice. 1063 let untyped_len = typed_len * 8; 1064 assert_eq!(Ref::bytes(&r).len(), untyped_len); 1065 assert_eq!(Ref::bytes(&r).as_ptr(), r.as_ptr().cast::<u8>()); 1066 1067 // Assert that values written to the typed value are reflected in the 1068 // byte slice. 1069 const VAL1: AU64 = AU64(0xFF00FF00FF00FF00); 1070 for typed in &mut *r { 1071 *typed = VAL1; 1072 } 1073 assert_eq!(Ref::bytes(&r), VAL1.0.to_ne_bytes().repeat(typed_len).as_slice()); 1074 1075 // Assert that values written to the byte slice are reflected in the 1076 // typed value. 1077 const VAL2: AU64 = AU64(!VAL1.0); // different from VAL1 1078 Ref::bytes_mut(&mut r).copy_from_slice(&VAL2.0.to_ne_bytes().repeat(typed_len)); 1079 assert!(r.iter().copied().all(|x| x == VAL2)); 1080 } 1081 1082 #[test] 1083 fn test_new_aligned_sized() { 1084 // Test that a properly-aligned, properly-sized buffer works for new, 1085 // new_from_prefix, and new_from_suffix, and that new_from_prefix and 1086 // new_from_suffix return empty slices. Test that a properly-aligned 1087 // buffer whose length is a multiple of the element size works for 1088 // new_slice. 1089 1090 // A buffer with an alignment of 8. 1091 let mut buf = Align::<[u8; 8], AU64>::default(); 1092 // `buf.t` should be aligned to 8, so this should always succeed. 1093 test_new_helper(Ref::<_, AU64>::from_bytes(&mut buf.t[..]).unwrap()); 1094 { 1095 // In a block so that `r` and `suffix` don't live too long. 1096 buf.set_default(); 1097 let (r, suffix) = Ref::<_, AU64>::from_prefix(&mut buf.t[..]).unwrap(); 1098 assert!(suffix.is_empty()); 1099 test_new_helper(r); 1100 } 1101 { 1102 buf.set_default(); 1103 let (prefix, r) = Ref::<_, AU64>::from_suffix(&mut buf.t[..]).unwrap(); 1104 assert!(prefix.is_empty()); 1105 test_new_helper(r); 1106 } 1107 1108 // A buffer with alignment 8 and length 24. We choose this length very 1109 // intentionally: if we instead used length 16, then the prefix and 1110 // suffix lengths would be identical. In the past, we used length 16, 1111 // which resulted in this test failing to discover the bug uncovered in 1112 // #506. 1113 let mut buf = Align::<[u8; 24], AU64>::default(); 1114 // `buf.t` should be aligned to 8 and have a length which is a multiple 1115 // of `size_of::<AU64>()`, so this should always succeed. 1116 test_new_helper_slice(Ref::<_, [AU64]>::from_bytes(&mut buf.t[..]).unwrap(), 3); 1117 buf.set_default(); 1118 let r = Ref::<_, [AU64]>::from_bytes_with_elems(&mut buf.t[..], 3).unwrap(); 1119 test_new_helper_slice(r, 3); 1120 1121 let ascending: [u8; 24] = (0..24).collect::<Vec<_>>().try_into().unwrap(); 1122 // 16 ascending bytes followed by 8 zeros. 1123 let mut ascending_prefix = ascending; 1124 ascending_prefix[16..].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); 1125 // 8 zeros followed by 16 ascending bytes. 1126 let mut ascending_suffix = ascending; 1127 ascending_suffix[..8].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); 1128 { 1129 buf.t = ascending_suffix; 1130 let (r, suffix) = Ref::<_, [AU64]>::from_prefix_with_elems(&mut buf.t[..], 1).unwrap(); 1131 assert_eq!(suffix, &ascending[8..]); 1132 test_new_helper_slice(r, 1); 1133 } 1134 { 1135 buf.t = ascending_prefix; 1136 let (prefix, r) = Ref::<_, [AU64]>::from_suffix_with_elems(&mut buf.t[..], 1).unwrap(); 1137 assert_eq!(prefix, &ascending[..16]); 1138 test_new_helper_slice(r, 1); 1139 } 1140 } 1141 1142 #[test] 1143 fn test_new_oversized() { 1144 // Test that a properly-aligned, overly-sized buffer works for 1145 // `new_from_prefix` and `new_from_suffix`, and that they return the 1146 // remainder and prefix of the slice respectively. 1147 1148 let mut buf = Align::<[u8; 16], AU64>::default(); 1149 { 1150 // In a block so that `r` and `suffix` don't live too long. `buf.t` 1151 // should be aligned to 8, so this should always succeed. 1152 let (r, suffix) = Ref::<_, AU64>::from_prefix(&mut buf.t[..]).unwrap(); 1153 assert_eq!(suffix.len(), 8); 1154 test_new_helper(r); 1155 } 1156 { 1157 buf.set_default(); 1158 // `buf.t` should be aligned to 8, so this should always succeed. 1159 let (prefix, r) = Ref::<_, AU64>::from_suffix(&mut buf.t[..]).unwrap(); 1160 assert_eq!(prefix.len(), 8); 1161 test_new_helper(r); 1162 } 1163 } 1164 1165 #[test] 1166 #[allow(clippy::cognitive_complexity)] 1167 fn test_new_error() { 1168 // Fail because the buffer is too large. 1169 1170 // A buffer with an alignment of 8. 1171 let buf = Align::<[u8; 16], AU64>::default(); 1172 // `buf.t` should be aligned to 8, so only the length check should fail. 1173 assert!(Ref::<_, AU64>::from_bytes(&buf.t[..]).is_err()); 1174 1175 // Fail because the buffer is too small. 1176 1177 // A buffer with an alignment of 8. 1178 let buf = Align::<[u8; 4], AU64>::default(); 1179 // `buf.t` should be aligned to 8, so only the length check should fail. 1180 assert!(Ref::<_, AU64>::from_bytes(&buf.t[..]).is_err()); 1181 assert!(Ref::<_, AU64>::from_prefix(&buf.t[..]).is_err()); 1182 assert!(Ref::<_, AU64>::from_suffix(&buf.t[..]).is_err()); 1183 1184 // Fail because the length is not a multiple of the element size. 1185 1186 let buf = Align::<[u8; 12], AU64>::default(); 1187 // `buf.t` has length 12, but element size is 8. 1188 assert!(Ref::<_, [AU64]>::from_bytes(&buf.t[..]).is_err()); 1189 1190 // Fail because the buffer is too short. 1191 let buf = Align::<[u8; 12], AU64>::default(); 1192 // `buf.t` has length 12, but the element size is 8 (and we're expecting 1193 // two of them). For each function, we test with a length that would 1194 // cause the size to overflow `usize`, and with a normal length that 1195 // will fail thanks to the buffer being too short; these are different 1196 // error paths, and while the error types are the same, the distinction 1197 // shows up in code coverage metrics. 1198 let n = (usize::MAX / mem::size_of::<AU64>()) + 1; 1199 assert!(Ref::<_, [AU64]>::from_bytes_with_elems(&buf.t[..], n).is_err()); 1200 assert!(Ref::<_, [AU64]>::from_bytes_with_elems(&buf.t[..], 2).is_err()); 1201 assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[..], n).is_err()); 1202 assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[..], 2).is_err()); 1203 assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[..], n).is_err()); 1204 assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[..], 2).is_err()); 1205 1206 // Fail because the alignment is insufficient. 1207 1208 // A buffer with an alignment of 8. An odd buffer size is chosen so that 1209 // the last byte of the buffer has odd alignment. 1210 let buf = Align::<[u8; 13], AU64>::default(); 1211 // Slicing from 1, we get a buffer with size 12 (so the length check 1212 // should succeed) but an alignment of only 1, which is insufficient. 1213 assert!(Ref::<_, AU64>::from_bytes(&buf.t[1..]).is_err()); 1214 assert!(Ref::<_, AU64>::from_prefix(&buf.t[1..]).is_err()); 1215 assert!(Ref::<_, [AU64]>::from_bytes(&buf.t[1..]).is_err()); 1216 assert!(Ref::<_, [AU64]>::from_bytes_with_elems(&buf.t[1..], 1).is_err()); 1217 assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[1..], 1).is_err()); 1218 assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[1..], 1).is_err()); 1219 // Slicing is unnecessary here because `new_from_suffix` uses the suffix 1220 // of the slice, which has odd alignment. 1221 assert!(Ref::<_, AU64>::from_suffix(&buf.t[..]).is_err()); 1222 1223 // Fail due to arithmetic overflow. 1224 1225 let buf = Align::<[u8; 16], AU64>::default(); 1226 let unreasonable_len = usize::MAX / mem::size_of::<AU64>() + 1; 1227 assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[..], unreasonable_len).is_err()); 1228 assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[..], unreasonable_len).is_err()); 1229 } 1230 1231 #[test] 1232 #[allow(unstable_name_collisions)] 1233 #[allow(clippy::as_conversions)] 1234 fn test_into_ref_mut() { 1235 #[allow(unused)] 1236 use crate::util::AsAddress as _; 1237 1238 let mut buf = Align::<[u8; 8], u64>::default(); 1239 let r = Ref::<_, u64>::from_bytes(&buf.t[..]).unwrap(); 1240 let rf = Ref::into_ref(r); 1241 assert_eq!(rf, &0u64); 1242 let buf_addr = (&buf.t as *const [u8; 8]).addr(); 1243 assert_eq!((rf as *const u64).addr(), buf_addr); 1244 1245 let r = Ref::<_, u64>::from_bytes(&mut buf.t[..]).unwrap(); 1246 let rf = Ref::into_mut(r); 1247 assert_eq!(rf, &mut 0u64); 1248 assert_eq!((rf as *mut u64).addr(), buf_addr); 1249 1250 *rf = u64::MAX; 1251 assert_eq!(buf.t, [0xFF; 8]); 1252 } 1253 1254 #[test] 1255 fn test_display_debug() { 1256 let buf = Align::<[u8; 8], u64>::default(); 1257 let r = Ref::<_, u64>::from_bytes(&buf.t[..]).unwrap(); 1258 assert_eq!(format!("{}", r), "0"); 1259 assert_eq!(format!("{:?}", r), "Ref(0)"); 1260 1261 let buf = Align::<[u8; 8], u64>::default(); 1262 let r = Ref::<_, [u64]>::from_bytes(&buf.t[..]).unwrap(); 1263 assert_eq!(format!("{:?}", r), "Ref([0])"); 1264 } 1265 1266 #[test] 1267 fn test_eq() { 1268 let buf1 = 0_u64; 1269 let r1 = Ref::<_, u64>::from_bytes(buf1.as_bytes()).unwrap(); 1270 let buf2 = 0_u64; 1271 let r2 = Ref::<_, u64>::from_bytes(buf2.as_bytes()).unwrap(); 1272 assert_eq!(r1, r2); 1273 } 1274 1275 #[test] 1276 fn test_ne() { 1277 let buf1 = 0_u64; 1278 let r1 = Ref::<_, u64>::from_bytes(buf1.as_bytes()).unwrap(); 1279 let buf2 = 1_u64; 1280 let r2 = Ref::<_, u64>::from_bytes(buf2.as_bytes()).unwrap(); 1281 assert_ne!(r1, r2); 1282 } 1283 1284 #[test] 1285 fn test_ord() { 1286 let buf1 = 0_u64; 1287 let r1 = Ref::<_, u64>::from_bytes(buf1.as_bytes()).unwrap(); 1288 let buf2 = 1_u64; 1289 let r2 = Ref::<_, u64>::from_bytes(buf2.as_bytes()).unwrap(); 1290 assert!(r1 < r2); 1291 assert_eq!(PartialOrd::partial_cmp(&r1, &r2), Some(Ordering::Less)); 1292 assert_eq!(Ord::cmp(&r1, &r2), Ordering::Less); 1293 } 1294 } 1295 1296 #[cfg(all(test, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS))] 1297 mod benches { 1298 use test::{self, Bencher}; 1299 1300 use super::*; 1301 use crate::util::testutil::*; 1302 1303 #[bench] 1304 fn bench_from_bytes_sized(b: &mut Bencher) { 1305 let buf = Align::<[u8; 8], AU64>::default(); 1306 // `buf.t` should be aligned to 8, so this should always succeed. 1307 let bytes = &buf.t[..]; 1308 b.iter(|| test::black_box(Ref::<_, AU64>::from_bytes(test::black_box(bytes)).unwrap())); 1309 } 1310 1311 #[bench] 1312 fn bench_into_ref_sized(b: &mut Bencher) { 1313 let buf = Align::<[u8; 8], AU64>::default(); 1314 let bytes = &buf.t[..]; 1315 let r = Ref::<_, AU64>::from_bytes(bytes).unwrap(); 1316 b.iter(|| test::black_box(Ref::into_ref(test::black_box(r)))); 1317 } 1318 1319 #[bench] 1320 fn bench_into_mut_sized(b: &mut Bencher) { 1321 let mut buf = Align::<[u8; 8], AU64>::default(); 1322 let buf = &mut buf.t[..]; 1323 let _ = Ref::<_, AU64>::from_bytes(&mut *buf).unwrap(); 1324 b.iter(move || { 1325 // SAFETY: The preceding `from_bytes` succeeded, and so we know that 1326 // `buf` is validly-aligned and has the correct length. 1327 let r = unsafe { Ref::<&mut [u8], AU64>::new_unchecked(&mut *buf) }; 1328 test::black_box(Ref::into_mut(test::black_box(r))); 1329 }); 1330 } 1331 1332 #[bench] 1333 fn bench_deref_sized(b: &mut Bencher) { 1334 let buf = Align::<[u8; 8], AU64>::default(); 1335 let bytes = &buf.t[..]; 1336 let r = Ref::<_, AU64>::from_bytes(bytes).unwrap(); 1337 b.iter(|| { 1338 let temp = test::black_box(r); 1339 test::black_box(temp.deref()); 1340 }); 1341 } 1342 1343 #[bench] 1344 fn bench_deref_mut_sized(b: &mut Bencher) { 1345 let mut buf = Align::<[u8; 8], AU64>::default(); 1346 let buf = &mut buf.t[..]; 1347 let _ = Ref::<_, AU64>::from_bytes(&mut *buf).unwrap(); 1348 b.iter(|| { 1349 // SAFETY: The preceding `from_bytes` succeeded, and so we know that 1350 // `buf` is validly-aligned and has the correct length. 1351 let r = unsafe { Ref::<&mut [u8], AU64>::new_unchecked(&mut *buf) }; 1352 let mut temp = test::black_box(r); 1353 test::black_box(temp.deref_mut()); 1354 }); 1355 } 1356 } 1357