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