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