zerocopy/ref.rs
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.
11use super::*;
12use crate::pointer::{
13 BecauseMutationCompatible, BecauseSharedCompatible, MutationCompatible, TransmuteFromPtr,
14};
15
16mod def {
17 use core::marker::PhantomData;
18
19 use crate::{
20 ByteSlice, ByteSliceMut, CloneableByteSlice, CopyableByteSlice, IntoByteSlice,
21 IntoByteSliceMut, KnownLayout, PointerMetadata,
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:
64 // - The referent (via `.deref`, `.deref_mut`, `.into`) byte slice is
65 // aligned to `T`'s alignment, and its size is valid for `T`.
66 // - If `T: KnownLayout`, let `metadata` be
67 // `T::PointerMetadata::from_elem_count` applied to `elem_count`.
68 // Then `T::size_for_metadata(metadata)` is `Some(referent.len())`.
69 bytes: B,
70 // Ignored when `T` does not implement `KnownLayout`.
71 elem_count: usize,
72 _marker: PhantomData<T>,
73 }
74
75 impl<B, T> Ref<B, T> {
76 /// Constructs a new `Ref` to a sized `T`.
77 ///
78 /// # Safety
79 ///
80 /// `bytes` dereferences (via [`deref`], [`deref_mut`], and [`into`]) to
81 /// a byte slice which is aligned to `T`'s alignment and whose size is
82 /// `size_of::<T>()`.
83 ///
84 /// [`deref`]: core::ops::Deref::deref
85 /// [`deref_mut`]: core::ops::DerefMut::deref_mut
86 /// [`into`]: core::convert::Into::into
87 pub(super) unsafe fn new_sized_unchecked(bytes: B) -> Ref<B, T> {
88 // INVARIANTS: The caller has promised that `bytes`'s referent is
89 // validly aligned and has size `size_of::<T>()`. If `T:
90 // KnownLayout`, then, since `T` is sized, `T::PointerMetadata` is
91 // `()`. `from_elem_count` returns `()` for any element count, and
92 // `T::size_for_metadata(()) == Some(size_of::<T>())`. `size_of`
93 // reports this size in bytes [1].
94 //
95 // [1] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.size_of.html:
96 //
97 // Returns the size of a type in bytes.
98 Ref { bytes, elem_count: 0, _marker: PhantomData }
99 }
100 }
101
102 impl<B, T: KnownLayout + ?Sized> Ref<B, T> {
103 /// Constructs a new `Ref`.
104 ///
105 /// # Safety
106 ///
107 /// `bytes` dereferences (via [`deref`], [`deref_mut`], and [`into`]) to
108 /// a byte slice which is aligned to `T`'s alignment and satisfies
109 /// `T::size_for_metadata(metadata) == Some(referent.len())`.
110 ///
111 /// [`deref`]: core::ops::Deref::deref
112 /// [`deref_mut`]: core::ops::DerefMut::deref_mut
113 /// [`into`]: core::convert::Into::into
114 pub(super) unsafe fn new_unchecked(bytes: B, metadata: T::PointerMetadata) -> Ref<B, T> {
115 // INVARIANTS: The caller has promised that `bytes`'s referent is
116 // validly aligned and has exactly the size described by `metadata`.
117 // `KnownLayout::PointerMetadata` is `()` for sized types and
118 // `usize` for slice DSTs. For both permitted metadata types,
119 // `from_elem_count(metadata.to_elem_count()) == metadata`: `()`
120 // round-trips through zero, while `usize` round-trips through
121 // itself. Thus, storing the element count preserves the metadata
122 // whose size the caller validated. This agrees with Rust's
123 // language-level definition of slice pointer metadata [1].
124 //
125 // [1] Per https://doc.rust-lang.org/1.56.0/reference/dynamically-sized-types.html:
126 //
127 // Pointers to slices also store the number of elements of the
128 // slice.
129 Ref { bytes, elem_count: metadata.to_elem_count(), _marker: PhantomData }
130 }
131
132 /// Gets the pointer metadata represented by this `Ref`.
133 #[inline(always)]
134 pub(super) fn pointer_metadata(&self) -> T::PointerMetadata {
135 // INVARIANTS: `KnownLayout::PointerMetadata` is either `()` or
136 // `usize`. For `()`, `from_elem_count` ignores the element count;
137 // for `usize`, it returns the element count unchanged.
138 T::PointerMetadata::from_elem_count(self.elem_count)
139 }
140 }
141
142 impl<B: ByteSlice, T: ?Sized> Ref<B, T> {
143 /// Access the byte slice as a [`ByteSlice`].
144 ///
145 /// # Safety
146 ///
147 /// The caller promises not to call methods on the returned
148 /// [`ByteSlice`] other than `ByteSlice` methods (for example, via
149 /// `Any::downcast_ref`).
150 ///
151 /// `as_byte_slice` promises to return a `ByteSlice` whose referent is
152 /// validly aligned for `T` and has a valid size for `T`. If `T:
153 /// KnownLayout`, then `T::size_for_metadata(self.pointer_metadata())`
154 /// returns `Some(referent.len())`.
155 pub(crate) unsafe fn as_byte_slice(&self) -> &impl ByteSlice {
156 // INVARIANTS: The caller promises not to call methods other than
157 // those on `ByteSlice`. Since `B: ByteSlice`, dereference stability
158 // guarantees that calling `ByteSlice` methods will not change the
159 // address or length of `self.bytes`'s referent.
160 //
161 // SAFETY: By invariant on `self`, the alignment, size, and metadata
162 // postconditions are upheld.
163 &self.bytes
164 }
165 }
166
167 impl<B: ByteSliceMut, T: ?Sized> Ref<B, T> {
168 /// Access the byte slice as a [`ByteSliceMut`].
169 ///
170 /// # Safety
171 ///
172 /// The caller promises not to call methods on the returned
173 /// [`ByteSliceMut`] other than `ByteSliceMut` methods (for example, via
174 /// `Any::downcast_mut`).
175 ///
176 /// `as_byte_slice_mut` promises to return a `ByteSliceMut` whose
177 /// referent is validly aligned for `T` and has a valid size for `T`. If
178 /// `T: KnownLayout`, then
179 /// `T::size_for_metadata(self.pointer_metadata())` returns
180 /// `Some(referent.len())`.
181 pub(crate) unsafe fn as_byte_slice_mut(&mut self) -> &mut impl ByteSliceMut {
182 // INVARIANTS: The caller promises not to call methods other than
183 // those on `ByteSliceMut`. Since `B: ByteSlice`, dereference
184 // stability guarantees that calling `ByteSlice` methods will not
185 // change the address or length of `self.bytes`'s referent.
186 //
187 // SAFETY: By invariant on `self`, the alignment, size, and metadata
188 // postconditions are upheld.
189 &mut self.bytes
190 }
191 }
192
193 impl<'a, B: IntoByteSlice<'a>, T: ?Sized> Ref<B, T> {
194 /// Access the byte slice as an [`IntoByteSlice`].
195 ///
196 /// # Safety
197 ///
198 /// The caller promises not to call methods on the returned
199 /// [`IntoByteSlice`] other than `IntoByteSlice` methods (for example,
200 /// via `Any::downcast_ref`).
201 ///
202 /// `into_byte_slice` promises to return an `IntoByteSlice` whose
203 /// referent is validly aligned for `T` and has a valid size for `T`. If
204 /// `T: KnownLayout`, then
205 /// `T::size_for_metadata(self.pointer_metadata())` returns
206 /// `Some(referent.len())`.
207 pub(crate) unsafe fn into_byte_slice(self) -> impl IntoByteSlice<'a> {
208 // INVARIANTS: The caller promises not to call methods other than
209 // those on `IntoByteSlice`. Since `B: ByteSlice`, dereference
210 // stability guarantees that calling `ByteSlice` methods will not
211 // change the address or length of `self.bytes`'s referent.
212 //
213 // SAFETY: By invariant on `self`, the alignment, size, and metadata
214 // postconditions are upheld.
215 self.bytes
216 }
217 }
218
219 impl<'a, B: IntoByteSliceMut<'a>, T: ?Sized> Ref<B, T> {
220 /// Access the byte slice as an [`IntoByteSliceMut`].
221 ///
222 /// # Safety
223 ///
224 /// The caller promises not to call methods on the returned
225 /// [`IntoByteSliceMut`] other than `IntoByteSliceMut` methods (for
226 /// example, via `Any::downcast_mut`).
227 ///
228 /// `into_byte_slice_mut` promises to return an `IntoByteSliceMut` whose
229 /// referent is validly aligned for `T` and has a valid size for `T`. If
230 /// `T: KnownLayout`, then
231 /// `T::size_for_metadata(self.pointer_metadata())` returns
232 /// `Some(referent.len())`.
233 pub(crate) unsafe fn into_byte_slice_mut(self) -> impl IntoByteSliceMut<'a> {
234 // INVARIANTS: The caller promises not to call methods other than
235 // those on `IntoByteSliceMut`. Since `B: ByteSlice`, dereference
236 // stability guarantees that calling `ByteSlice` methods will not
237 // change the address or length of `self.bytes`'s referent.
238 //
239 // SAFETY: By invariant on `self`, the alignment, size, and metadata
240 // postconditions are upheld.
241 self.bytes
242 }
243 }
244
245 impl<B: CloneableByteSlice + Clone, T: ?Sized> Clone for Ref<B, T> {
246 #[inline]
247 fn clone(&self) -> Ref<B, T> {
248 // INVARIANTS: Since `B: CloneableByteSlice`, `self.bytes.clone()` has
249 // the same address and length as `self.bytes`. We copy
250 // `self.elem_count`, so the clone also has the same metadata. Since
251 // `self` upholds the field invariants, so does the clone.
252 Ref { bytes: self.bytes.clone(), elem_count: self.elem_count, _marker: PhantomData }
253 }
254 }
255
256 // INVARIANTS: Since `B: CopyableByteSlice`, the copied `Ref`'s `bytes` has the
257 // same address and length as the original `Ref`'s `bytes`. The copied
258 // `elem_count` has the same metadata. Since the original upholds the field
259 // invariants, so does the copy.
260 impl<B: CopyableByteSlice + Copy, T: ?Sized> Copy for Ref<B, T> {}
261}
262
263#[allow(unreachable_pub)] // This is a false positive on our MSRV toolchain.
264pub use def::Ref;
265
266use crate::pointer::{
267 invariant::{Aligned, BecauseExclusive, Initialized, Safe, Unaligned},
268 BecauseRead, PtrInner,
269};
270
271impl<B, T> Ref<B, T>
272where
273 B: ByteSlice,
274{
275 #[must_use = "has no side effects"]
276 pub(crate) fn sized_from(bytes: B) -> Result<Ref<B, T>, CastError<B, T>> {
277 if bytes.len() != mem::size_of::<T>() {
278 return Err(SizeError::new(bytes).into());
279 }
280 if let Err(err) = util::validate_aligned_to::<_, T>(bytes.deref()) {
281 return Err(err.with_src(bytes).into());
282 }
283
284 // SAFETY: `size_of` returns `T`'s size in bytes [1]. The equality check
285 // above therefore establishes that `bytes` has exactly that byte
286 // length, and `validate_aligned_to` establishes alignment.
287 //
288 // [1] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.size_of.html:
289 //
290 // Returns the size of a type in bytes.
291 Ok(unsafe { Ref::new_sized_unchecked(bytes) })
292 }
293}
294
295impl<B, T> Ref<B, T>
296where
297 B: SplitByteSlice,
298{
299 #[must_use = "has no side effects"]
300 pub(crate) fn sized_from_prefix(bytes: B) -> Result<(Ref<B, T>, B), CastError<B, T>> {
301 if bytes.len() < mem::size_of::<T>() {
302 return Err(SizeError::new(bytes).into());
303 }
304 if let Err(err) = util::validate_aligned_to::<_, T>(bytes.deref()) {
305 return Err(err.with_src(bytes).into());
306 }
307 let (bytes, suffix) = bytes.split_at(mem::size_of::<T>()).map_err(
308 #[inline(always)]
309 |b| SizeError::new(b).into(),
310 )?;
311 // SAFETY: We just validated alignment and that `bytes` is at least as
312 // large as `T`. `bytes.split_at(mem::size_of::<T>())?` ensures that the
313 // new `bytes` is exactly the size of `T`, measured in bytes as specified
314 // for `size_of` [1]. By safety postcondition on
315 // `SplitByteSlice::split_at` we can rely on `split_at` to produce the
316 // correct `bytes` and `suffix`.
317 //
318 // [1] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.size_of.html:
319 //
320 // Returns the size of a type in bytes.
321 let r = unsafe { Ref::new_sized_unchecked(bytes) };
322 Ok((r, suffix))
323 }
324
325 #[must_use = "has no side effects"]
326 pub(crate) fn sized_from_suffix(bytes: B) -> Result<(B, Ref<B, T>), CastError<B, T>> {
327 let bytes_len = bytes.len();
328 let split_at = if let Some(split_at) = bytes_len.checked_sub(mem::size_of::<T>()) {
329 split_at
330 } else {
331 return Err(SizeError::new(bytes).into());
332 };
333 let (prefix, bytes) = bytes.split_at(split_at).map_err(|b| SizeError::new(b).into())?;
334 if let Err(err) = util::validate_aligned_to::<_, T>(bytes.deref()) {
335 return Err(err.with_src(bytes).into());
336 }
337 // SAFETY: Since `split_at` is defined as `bytes_len - size_of::<T>()`,
338 // the `bytes` which results from `let (prefix, bytes) =
339 // bytes.split_at(split_at)?` has length `size_of::<T>()`, measured in
340 // bytes as specified for `size_of` [1]. After constructing `bytes`, we
341 // validate that it has the proper alignment. By safety postcondition on
342 // `SplitByteSlice::split_at` we can rely on `split_at` to produce the
343 // correct `prefix` and `bytes`.
344 //
345 // [1] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.size_of.html:
346 //
347 // Returns the size of a type in bytes.
348 let r = unsafe { Ref::new_sized_unchecked(bytes) };
349 Ok((prefix, r))
350 }
351}
352
353impl<B, T> Ref<B, T>
354where
355 B: ByteSlice,
356 T: KnownLayout + Immutable + ?Sized,
357{
358 /// Constructs a `Ref` from a byte slice.
359 ///
360 /// If the length of `source` is not a [valid size of `T`][valid-size], or
361 /// if `source` is not appropriately aligned for `T`, this returns `Err`. If
362 /// [`T: Unaligned`][t-unaligned], you can [infallibly discard the alignment
363 /// error][size-error-from].
364 ///
365 /// `T` may be a sized type, a slice, or a [slice DST][slice-dst].
366 ///
367 /// [valid-size]: crate::KnownLayout#what-is-a-valid-size
368 /// [t-unaligned]: crate::Unaligned
369 /// [size-error-from]: error/struct.SizeError.html#method.from-1
370 /// [slice-dst]: KnownLayout#dynamically-sized-types
371 ///
372 /// # Compile-Time Assertions
373 ///
374 /// This method cannot yet be used on unsized types whose dynamically-sized
375 /// component is zero-sized. Attempting to use this method on such types
376 /// results in a compile-time assertion error; e.g.:
377 ///
378 /// ```compile_fail,E0080
379 /// use zerocopy::*;
380 /// # use zerocopy_derive::*;
381 ///
382 /// #[derive(Immutable, KnownLayout)]
383 /// #[repr(C)]
384 /// struct ZSTy {
385 /// leading_sized: u16,
386 /// trailing_dst: [()],
387 /// }
388 ///
389 /// let _ = Ref::<_, ZSTy>::from_bytes(&b"UU"[..]); // ⚠ Compile Error!
390 /// ```
391 ///
392 #[doc = codegen_section!(
393 header = "h5",
394 bench = "ref_type_from_bytes",
395 format = "coco",
396 arity = 3,
397 [
398 open
399 @index 1
400 @title "Sized"
401 @variant "static_size"
402 ],
403 [
404 @index 2
405 @title "Unsized"
406 @variant "dynamic_size"
407 ],
408 [
409 @index 3
410 @title "Dynamically Padded"
411 @variant "dynamic_padding"
412 ]
413 )]
414 #[must_use = "has no side effects"]
415 #[inline]
416 pub fn from_bytes(source: B) -> Result<Ref<B, T>, CastError<B, T>> {
417 static_assert_dst_is_not_zst!(T);
418 let metadata = match Ptr::from_ref(source.deref())
419 .try_cast_into_no_leftover::<T, BecauseImmutable>(None)
420 {
421 Ok(ptr) => T::pointer_to_metadata(ptr.as_inner().as_ptr()),
422 Err(e) => return Err(e.with_src(()).with_src(source)),
423 };
424 // SAFETY: By its safety postcondition, `try_cast_into_no_leftover`
425 // returned a `Ptr<T>` aligned as required for references [2], over the
426 // same byte range as `source.deref()`. `pointer_to_metadata` returns
427 // the metadata stored in that pointer, and `size_for_metadata` computes
428 // the corresponding dynamically-known byte size [1]. Thus,
429 // `T::size_for_metadata(metadata)` is `Some(source.len())`.
430 // `ByteSlice` and its applicable subtraits guarantee that the stored
431 // `source` continues to dereference or convert to that address and
432 // length. These facts establish both preconditions of `new_unchecked`.
433 //
434 // [1] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.size_of_val.html:
435 //
436 // Returns the size of the pointed-to value in bytes.
437 //
438 // ... when `T` has no statically-known size ... `size_of_val` can
439 // be used to get the dynamically-known size.
440 //
441 // [2] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.align_of_val.html:
442 //
443 // Returns the ABI-required minimum alignment of the type of the
444 // value that `val` points to.
445 //
446 // Every reference to a value of the type `T` must be a multiple of
447 // this number.
448 Ok(unsafe { Ref::new_unchecked(source, metadata) })
449 }
450}
451
452impl<B, T> Ref<B, T>
453where
454 B: SplitByteSlice,
455 T: KnownLayout + Immutable + ?Sized,
456{
457 /// Constructs a `Ref` from the prefix of a byte slice.
458 ///
459 /// This method computes the [largest possible size of `T`][valid-size] that
460 /// can fit in the leading bytes of `source`, then attempts to return both a
461 /// `Ref` to those bytes, and a reference to the remaining bytes. If there
462 /// are insufficient bytes, or if `source` is not appropriately aligned,
463 /// this returns `Err`. If [`T: Unaligned`][t-unaligned], you can
464 /// [infallibly discard the alignment error][size-error-from].
465 ///
466 /// `T` may be a sized type, a slice, or a [slice DST][slice-dst].
467 ///
468 /// [valid-size]: crate::KnownLayout#what-is-a-valid-size
469 /// [t-unaligned]: crate::Unaligned
470 /// [size-error-from]: error/struct.SizeError.html#method.from-1
471 /// [slice-dst]: KnownLayout#dynamically-sized-types
472 ///
473 /// # Compile-Time Assertions
474 ///
475 /// This method cannot yet be used on unsized types whose dynamically-sized
476 /// component is zero-sized. Attempting to use this method on such types
477 /// results in a compile-time assertion error; e.g.:
478 ///
479 /// ```compile_fail,E0080
480 /// use zerocopy::*;
481 /// # use zerocopy_derive::*;
482 ///
483 /// #[derive(Immutable, KnownLayout)]
484 /// #[repr(C)]
485 /// struct ZSTy {
486 /// leading_sized: u16,
487 /// trailing_dst: [()],
488 /// }
489 ///
490 /// let _ = Ref::<_, ZSTy>::from_prefix(&b"UU"[..]); // ⚠ Compile Error!
491 /// ```
492 ///
493 #[doc = codegen_section!(
494 header = "h5",
495 bench = "ref_type_from_prefix",
496 format = "coco",
497 arity = 3,
498 [
499 open
500 @index 1
501 @title "Sized"
502 @variant "static_size"
503 ],
504 [
505 @index 2
506 @title "Unsized"
507 @variant "dynamic_size"
508 ],
509 [
510 @index 3
511 @title "Dynamically Padded"
512 @variant "dynamic_padding"
513 ]
514 )]
515 #[must_use = "has no side effects"]
516 #[inline]
517 pub fn from_prefix(source: B) -> Result<(Ref<B, T>, B), CastError<B, T>> {
518 static_assert_dst_is_not_zst!(T);
519 let (metadata, remainder) = match Ptr::from_ref(source.deref())
520 .try_cast_into::<T, BecauseImmutable>(CastType::Prefix, None)
521 {
522 Ok((ptr, remainder)) => (T::pointer_to_metadata(ptr.as_inner().as_ptr()), remainder),
523 Err(e) => {
524 return Err(e.with_src(()).with_src(source));
525 }
526 };
527
528 // SAFETY: `remainder` is constructed as a subset of `source`, and so it
529 // cannot have a larger size than `source`. Both of their `len` methods
530 // measure bytes (`source` deref's to `[u8]`, and `remainder` is a
531 // `Ptr<[u8]>`), so `source.len() >= remainder.len()`. Thus, this cannot
532 // underflow.
533 #[allow(unstable_name_collisions)]
534 let split_at = unsafe { source.len().unchecked_sub(remainder.len()) };
535 let (bytes, suffix) = source.split_at(split_at).map_err(|b| SizeError::new(b).into())?;
536 // SAFETY: By its safety postcondition, `try_cast_into` returned an
537 // `Ptr<T>` aligned as required for references [2], and a remainder
538 // which are non-overlapping, cover `source.deref()`, and place the
539 // `Ptr<T>` at `source.deref()`'s address.
540 // Therefore, `split_at` is the typed pointer's byte length. By the
541 // safety postcondition of `SplitByteSlice::split_at`, `bytes` has that
542 // length and address. `pointer_to_metadata` returns the metadata stored
543 // in the typed pointer, and `size_for_metadata` computes the
544 // corresponding dynamically-known byte size [1]. Thus,
545 // `T::size_for_metadata(metadata)` is `Some(bytes.len())`. The
546 // `SplitByteSlice` and `ByteSlice` contracts preserve the established
547 // address and length, satisfying both preconditions of
548 // `new_unchecked`.
549 //
550 // [1] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.size_of_val.html:
551 //
552 // Returns the size of the pointed-to value in bytes.
553 //
554 // ... when `T` has no statically-known size ... `size_of_val` can
555 // be used to get the dynamically-known size.
556 //
557 // [2] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.align_of_val.html:
558 //
559 // Returns the ABI-required minimum alignment of the type of the
560 // value that `val` points to.
561 //
562 // Every reference to a value of the type `T` must be a multiple of
563 // this number.
564 let r = unsafe { Ref::new_unchecked(bytes, metadata) };
565 Ok((r, suffix))
566 }
567
568 /// Constructs a `Ref` from the suffix of a byte slice.
569 ///
570 /// This method computes the [largest possible size of `T`][valid-size] that
571 /// can fit in the trailing bytes of `source`, then attempts to return both
572 /// a `Ref` to those bytes, and a reference to the preceding bytes. If there
573 /// are insufficient bytes, or if that suffix of `source` is not
574 /// appropriately aligned, this returns `Err`. If [`T:
575 /// Unaligned`][t-unaligned], you can [infallibly discard the alignment
576 /// error][size-error-from].
577 ///
578 /// `T` may be a sized type, a slice, or a [slice DST][slice-dst].
579 ///
580 /// [valid-size]: crate::KnownLayout#what-is-a-valid-size
581 /// [t-unaligned]: crate::Unaligned
582 /// [size-error-from]: error/struct.SizeError.html#method.from-1
583 /// [slice-dst]: KnownLayout#dynamically-sized-types
584 ///
585 /// # Compile-Time Assertions
586 ///
587 /// This method cannot yet be used on unsized types whose dynamically-sized
588 /// component is zero-sized. Attempting to use this method on such types
589 /// results in a compile-time assertion error; e.g.:
590 ///
591 /// ```compile_fail,E0080
592 /// use zerocopy::*;
593 /// # use zerocopy_derive::*;
594 ///
595 /// #[derive(Immutable, KnownLayout)]
596 /// #[repr(C)]
597 /// struct ZSTy {
598 /// leading_sized: u16,
599 /// trailing_dst: [()],
600 /// }
601 ///
602 /// let _ = Ref::<_, ZSTy>::from_suffix(&b"UU"[..]); // ⚠ Compile Error!
603 /// ```
604 ///
605 #[doc = codegen_section!(
606 header = "h5",
607 bench = "ref_type_from_suffix",
608 format = "coco",
609 arity = 3,
610 [
611 open
612 @index 1
613 @title "Sized"
614 @variant "static_size"
615 ],
616 [
617 @index 2
618 @title "Unsized"
619 @variant "dynamic_size"
620 ],
621 [
622 @index 3
623 @title "Dynamically Padded"
624 @variant "dynamic_padding"
625 ]
626 )]
627 #[must_use = "has no side effects"]
628 #[inline]
629 pub fn from_suffix(source: B) -> Result<(B, Ref<B, T>), CastError<B, T>> {
630 static_assert_dst_is_not_zst!(T);
631 let (metadata, remainder) = match Ptr::from_ref(source.deref())
632 .try_cast_into::<T, BecauseImmutable>(CastType::Suffix, None)
633 {
634 Ok((ptr, remainder)) => (T::pointer_to_metadata(ptr.as_inner().as_ptr()), remainder),
635 Err(e) => {
636 let e = e.with_src(());
637 return Err(e.with_src(source));
638 }
639 };
640
641 let split_at = remainder.len();
642 let (prefix, bytes) = source.split_at(split_at).map_err(|b| SizeError::new(b).into())?;
643 // SAFETY: By its safety postcondition, `try_cast_into` returned an
644 // `Ptr<T>` aligned as required for references [2], and a remainder
645 // which are non-overlapping, cover `source.deref()`, and place the
646 // remainder at `source.deref()`'s address. More precisely,
647 // `PtrInner::try_cast_into` constructs the typed suffix from the
648 // `r_slice` produced by `split_at_unchecked(split_at)` and returns its
649 // `l_slice` as `remainder`. Thus, even when `T` is zero-sized, the typed
650 // pointer and the `bytes` produced by splitting `source` at
651 // `remainder.len()` have the same address and length. By the safety
652 // postcondition of `SplitByteSlice::split_at`, `bytes` retains that
653 // address and length. `pointer_to_metadata` returns the metadata stored
654 // in the typed pointer, and `size_for_metadata` computes the
655 // corresponding dynamically-known byte size [1]. Thus,
656 // `T::size_for_metadata(metadata)` is `Some(bytes.len())`. The
657 // `SplitByteSlice` and `ByteSlice` contracts preserve the established
658 // address and length, satisfying both preconditions of
659 // `new_unchecked`.
660 //
661 // [1] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.size_of_val.html:
662 //
663 // Returns the size of the pointed-to value in bytes.
664 //
665 // ... when `T` has no statically-known size ... `size_of_val` can
666 // be used to get the dynamically-known size.
667 //
668 // [2] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.align_of_val.html:
669 //
670 // Returns the ABI-required minimum alignment of the type of the
671 // value that `val` points to.
672 //
673 // Every reference to a value of the type `T` must be a multiple of
674 // this number.
675 let r = unsafe { Ref::new_unchecked(bytes, metadata) };
676 Ok((prefix, r))
677 }
678}
679
680impl<B, T> Ref<B, T>
681where
682 B: ByteSlice,
683 T: KnownLayout<PointerMetadata = usize> + Immutable + ?Sized,
684{
685 /// Constructs a `Ref` from the given bytes with DST length equal to `count`
686 /// without copying.
687 ///
688 /// This method attempts to return a `Ref` to the prefix of `source`
689 /// interpreted as a `T` with `count` trailing elements, and a reference to
690 /// the remaining bytes. If the length of `source` is not equal to the size
691 /// of `Self` with `count` elements, or if `source` is not appropriately
692 /// aligned, this returns `Err`. If [`T: Unaligned`][t-unaligned], you can
693 /// [infallibly discard the alignment error][size-error-from].
694 ///
695 /// [t-unaligned]: crate::Unaligned
696 /// [size-error-from]: error/struct.SizeError.html#method.from-1
697 ///
698 /// # Compile-Time Assertions
699 ///
700 /// This method cannot yet be used on unsized types whose dynamically-sized
701 /// component is zero-sized. Attempting to use this method on such types
702 /// results in a compile-time assertion error; e.g.:
703 ///
704 /// ```compile_fail,E0080
705 /// use zerocopy::*;
706 /// # use zerocopy_derive::*;
707 ///
708 /// #[derive(Immutable, KnownLayout)]
709 /// #[repr(C)]
710 /// struct ZSTy {
711 /// leading_sized: u16,
712 /// trailing_dst: [()],
713 /// }
714 ///
715 /// let _ = Ref::<_, ZSTy>::from_bytes_with_elems(&b"UU"[..], 42); // ⚠ Compile Error!
716 /// ```
717 ///
718 #[doc = codegen_section!(
719 header = "h5",
720 bench = "ref_type_from_bytes_with_elems",
721 format = "coco",
722 arity = 2,
723 [
724 open
725 @index 1
726 @title "Unsized"
727 @variant "dynamic_size"
728 ],
729 [
730 @index 2
731 @title "Dynamically Padded"
732 @variant "dynamic_padding"
733 ]
734 )]
735 #[inline]
736 pub fn from_bytes_with_elems(source: B, count: usize) -> Result<Ref<B, T>, CastError<B, T>> {
737 static_assert_dst_is_not_zst!(T);
738 let expected_len = match T::size_for_metadata(count) {
739 Some(len) => len,
740 None => return Err(SizeError::new(source).into()),
741 };
742 if source.len() != expected_len {
743 return Err(SizeError::new(source).into());
744 }
745 if let Err(e) = Ptr::from_ref(source.deref())
746 .try_cast_into_no_leftover::<T, BecauseImmutable>(Some(count))
747 {
748 return Err(e.with_src(()).with_src(source));
749 }
750 // SAFETY: `size_for_metadata(count)` returned `expected_len`, and the
751 // equality check established that this is `source.len()`. This is the
752 // dynamically-known byte size described by `size_of_val` [1]. By its
753 // safety postcondition, `try_cast_into_no_leftover(Some(count))` only
754 // succeeded after producing a `Ptr<T>` aligned as required for
755 // references [2], with that metadata over the same byte range as
756 // `source.deref()`. `ByteSlice` and its applicable subtraits guarantee
757 // that the stored `source` continues to dereference or convert to that
758 // address and length. These facts establish both preconditions of
759 // `new_unchecked`.
760 //
761 // [1] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.size_of_val.html:
762 //
763 // Returns the size of the pointed-to value in bytes.
764 //
765 // ... when `T` has no statically-known size ... `size_of_val` can
766 // be used to get the dynamically-known size.
767 //
768 // [2] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.align_of_val.html:
769 //
770 // Returns the ABI-required minimum alignment of the type of the
771 // value that `val` points to.
772 //
773 // Every reference to a value of the type `T` must be a multiple of
774 // this number.
775 Ok(unsafe { Ref::new_unchecked(source, count) })
776 }
777}
778
779impl<B, T> Ref<B, T>
780where
781 B: SplitByteSlice,
782 T: KnownLayout<PointerMetadata = usize> + Immutable + ?Sized,
783{
784 /// Constructs a `Ref` from the prefix of the given bytes with DST
785 /// length equal to `count` without copying.
786 ///
787 /// This method attempts to return a `Ref` to the prefix of `source`
788 /// interpreted as a `T` with `count` trailing elements, and a reference to
789 /// the remaining bytes. If there are insufficient bytes, or if `source` is
790 /// not appropriately aligned, this returns `Err`. If [`T:
791 /// Unaligned`][t-unaligned], you can [infallibly discard the alignment
792 /// error][size-error-from].
793 ///
794 /// [t-unaligned]: crate::Unaligned
795 /// [size-error-from]: error/struct.SizeError.html#method.from-1
796 ///
797 /// # Compile-Time Assertions
798 ///
799 /// This method cannot yet be used on unsized types whose dynamically-sized
800 /// component is zero-sized. Attempting to use this method on such types
801 /// results in a compile-time assertion error; e.g.:
802 ///
803 /// ```compile_fail,E0080
804 /// use zerocopy::*;
805 /// # use zerocopy_derive::*;
806 ///
807 /// #[derive(Immutable, KnownLayout)]
808 /// #[repr(C)]
809 /// struct ZSTy {
810 /// leading_sized: u16,
811 /// trailing_dst: [()],
812 /// }
813 ///
814 /// let _ = Ref::<_, ZSTy>::from_prefix_with_elems(&b"UU"[..], 42); // ⚠ Compile Error!
815 /// ```
816 ///
817 #[doc = codegen_section!(
818 header = "h5",
819 bench = "ref_type_from_prefix_with_elems",
820 format = "coco",
821 arity = 2,
822 [
823 open
824 @index 1
825 @title "Unsized"
826 @variant "dynamic_size"
827 ],
828 [
829 @index 2
830 @title "Dynamically Padded"
831 @variant "dynamic_padding"
832 ]
833 )]
834 #[inline]
835 pub fn from_prefix_with_elems(
836 source: B,
837 count: usize,
838 ) -> Result<(Ref<B, T>, B), CastError<B, T>> {
839 static_assert_dst_is_not_zst!(T);
840 let expected_len = match T::size_for_metadata(count) {
841 Some(len) => len,
842 None => return Err(SizeError::new(source).into()),
843 };
844 let (prefix, bytes) = source.split_at(expected_len).map_err(SizeError::new)?;
845 Self::from_bytes_with_elems(prefix, count).map(move |l| (l, bytes))
846 }
847
848 /// Constructs a `Ref` from the suffix of the given bytes with DST length
849 /// equal to `count` without copying.
850 ///
851 /// This method attempts to return a `Ref` to the suffix of `source`
852 /// interpreted as a `T` with `count` trailing elements, and a reference to
853 /// the preceding bytes. If there are insufficient bytes, or if that suffix
854 /// of `source` is not appropriately aligned, this returns `Err`. If [`T:
855 /// Unaligned`][t-unaligned], you can [infallibly discard the alignment
856 /// error][size-error-from].
857 ///
858 /// [t-unaligned]: crate::Unaligned
859 /// [size-error-from]: error/struct.SizeError.html#method.from-1
860 ///
861 /// # Compile-Time Assertions
862 ///
863 /// This method cannot yet be used on unsized types whose dynamically-sized
864 /// component is zero-sized. Attempting to use this method on such types
865 /// results in a compile-time assertion error; e.g.:
866 ///
867 /// ```compile_fail,E0080
868 /// use zerocopy::*;
869 /// # use zerocopy_derive::*;
870 ///
871 /// #[derive(Immutable, KnownLayout)]
872 /// #[repr(C)]
873 /// struct ZSTy {
874 /// leading_sized: u16,
875 /// trailing_dst: [()],
876 /// }
877 ///
878 /// let _ = Ref::<_, ZSTy>::from_suffix_with_elems(&b"UU"[..], 42); // ⚠ Compile Error!
879 /// ```
880 ///
881 #[doc = codegen_section!(
882 header = "h5",
883 bench = "ref_type_from_suffix_with_elems",
884 format = "coco",
885 arity = 2,
886 [
887 open
888 @index 1
889 @title "Unsized"
890 @variant "dynamic_size"
891 ],
892 [
893 @index 2
894 @title "Dynamically Padded"
895 @variant "dynamic_padding"
896 ]
897 )]
898 #[inline]
899 pub fn from_suffix_with_elems(
900 source: B,
901 count: usize,
902 ) -> Result<(B, Ref<B, T>), CastError<B, T>> {
903 static_assert_dst_is_not_zst!(T);
904 let expected_len = match T::size_for_metadata(count) {
905 Some(len) => len,
906 None => return Err(SizeError::new(source).into()),
907 };
908 let split_at = if let Some(split_at) = source.len().checked_sub(expected_len) {
909 split_at
910 } else {
911 return Err(SizeError::new(source).into());
912 };
913 // SAFETY: The preceding `source.len().checked_sub(expected_len)`
914 // guarantees that `split_at` is in-bounds.
915 let (bytes, suffix) = unsafe { source.split_at_unchecked(split_at) };
916 Self::from_bytes_with_elems(suffix, count).map(move |l| (bytes, l))
917 }
918}
919
920impl<'a, B, T> Ref<B, T>
921where
922 B: 'a + IntoByteSlice<'a>,
923 T: FromBytes + KnownLayout + Immutable + ?Sized,
924{
925 /// Converts this `Ref` into a reference.
926 ///
927 /// `into_ref` consumes the `Ref`, and returns a reference to `T`.
928 ///
929 /// Note: this is an associated function, which means that you have to call
930 /// it as `Ref::into_ref(r)` instead of `r.into_ref()`. This is so that
931 /// there is no conflict with a method on the inner type.
932 ///
933 #[doc = codegen_section!(
934 header = "h5",
935 bench = "ref_type_into_ref",
936 format = "coco",
937 arity = 3,
938 [
939 open
940 @index 1
941 @title "Sized"
942 @variant "static_size"
943 ],
944 [
945 @index 2
946 @title "Unsized"
947 @variant "dynamic_size"
948 ],
949 [
950 @index 3
951 @title "Dynamically Padded"
952 @variant "dynamic_padding"
953 ]
954 )]
955 #[must_use = "has no side effects"]
956 #[inline(always)]
957 pub fn into_ref(r: Self) -> &'a T {
958 // Presumably unreachable, since we've guarded each constructor of `Ref`.
959 static_assert_dst_is_not_zst!(T);
960
961 let metadata = r.pointer_metadata();
962
963 // SAFETY: We don't call any methods on `b` other than those provided by
964 // `IntoByteSlice`.
965 let b = unsafe { r.into_byte_slice() };
966 let b = b.into_byte_slice();
967
968 if let crate::layout::SizeInfo::Sized { .. } = T::LAYOUT.size_info {
969 let ptr = Ptr::from_ref(b);
970 // SAFETY: We just checked that `T: Sized`. By invariant on `r`,
971 // `b`'s size is equal to `size_of::<T>()`.
972 let ptr = unsafe { cast_for_sized::<T, _, _, _>(ptr) };
973
974 // SAFETY: None of the preceding transformations modifies the
975 // address of the pointer, and by invariant on `r`, we know that it
976 // is validly-aligned.
977 let ptr = unsafe { ptr.assume_alignment::<Aligned>() };
978 return ptr.as_ref();
979 }
980
981 // PANICS: By post-condition on `into_byte_slice`, `b` is aligned for
982 // `T`, and its size is exactly the size encoded by `metadata`. By
983 // post-condition, `b.into_byte_slice()` produces a byte slice with
984 // identical address and length to that produced by `b.deref()`.
985 let ptr = Ptr::from_ref(b.into_byte_slice())
986 .try_cast_into_no_leftover::<T, BecauseImmutable>(Some(metadata))
987 .expect("zerocopy internal error: into_ref should be infallible");
988 let ptr = ptr.recall_validity();
989 ptr.as_ref()
990 }
991}
992
993impl<'a, B, T> Ref<B, T>
994where
995 B: 'a + IntoByteSliceMut<'a>,
996 T: FromBytes + IntoBytes + KnownLayout + ?Sized,
997{
998 /// Converts this `Ref` into a mutable reference.
999 ///
1000 /// `into_mut` consumes the `Ref`, and returns a mutable reference to `T`.
1001 ///
1002 /// Note: this is an associated function, which means that you have to call
1003 /// it as `Ref::into_mut(r)` instead of `r.into_mut()`. This is so that
1004 /// there is no conflict with a method on the inner type.
1005 ///
1006 #[doc = codegen_section!(
1007 header = "h5",
1008 bench = "ref_type_into_mut",
1009 format = "coco",
1010 arity = 2,
1011 [
1012 open
1013 @index 1
1014 @title "Sized"
1015 @variant "static_size"
1016 ],
1017 [
1018 @index 2
1019 @title "Unsized"
1020 @variant "dynamic_size"
1021 ]
1022 )]
1023 #[must_use = "has no side effects"]
1024 #[inline(always)]
1025 pub fn into_mut(r: Self) -> &'a mut T {
1026 // Presumably unreachable, since we've guarded each constructor of `Ref`.
1027 static_assert_dst_is_not_zst!(T);
1028
1029 let metadata = r.pointer_metadata();
1030
1031 // SAFETY: We don't call any methods on `b` other than those provided by
1032 // `IntoByteSliceMut`.
1033 let b = unsafe { r.into_byte_slice_mut() };
1034 let b = b.into_byte_slice_mut();
1035
1036 if let crate::layout::SizeInfo::Sized { .. } = T::LAYOUT.size_info {
1037 let ptr = Ptr::from_mut(b);
1038 // SAFETY: We just checked that `T: Sized`. By invariant on `r`,
1039 // `b`'s size is equal to `size_of::<T>()`.
1040 let ptr = unsafe {
1041 cast_for_sized::<
1042 T,
1043 _,
1044 (BecauseRead, BecauseExclusive),
1045 (BecauseMutationCompatible, BecauseSharedCompatible),
1046 >(ptr)
1047 };
1048
1049 // SAFETY: None of the preceding transformations modifies the
1050 // address of the pointer, and by invariant on `r`, we know that it
1051 // is validly-aligned.
1052 let ptr = unsafe { ptr.assume_alignment::<Aligned>() };
1053 return ptr.as_mut();
1054 }
1055
1056 // PANICS: By post-condition on `into_byte_slice_mut`, `b` is aligned
1057 // for `T`, and its size is exactly the size encoded by `metadata`. By
1058 // post-condition, `b.into_byte_slice_mut()` produces a byte slice with
1059 // identical address and length to that produced by `b.deref_mut()`.
1060 let ptr = Ptr::from_mut(b.into_byte_slice_mut())
1061 .try_cast_into_no_leftover::<T, BecauseExclusive>(Some(metadata))
1062 .expect("zerocopy internal error: into_mut should be infallible");
1063 let ptr = ptr.recall_validity::<_, (_, (_, _))>();
1064 ptr.as_mut()
1065 }
1066}
1067
1068impl<B, T> Ref<B, T>
1069where
1070 B: ByteSlice,
1071 T: ?Sized,
1072{
1073 /// Gets the underlying bytes.
1074 ///
1075 /// Note: this is an associated function, which means that you have to call
1076 /// it as `Ref::bytes(r)` instead of `r.bytes()`. This is so that there is
1077 /// no conflict with a method on the inner type.
1078 ///
1079 #[doc = codegen_section!(
1080 header = "h5",
1081 bench = "ref_type_bytes",
1082 format = "coco",
1083 arity = 3,
1084 [
1085 open
1086 @index 1
1087 @title "Sized"
1088 @variant "static_size"
1089 ],
1090 [
1091 @index 2
1092 @title "Unsized"
1093 @variant "dynamic_size"
1094 ],
1095 [
1096 @index 3
1097 @title "Dynamically Padded"
1098 @variant "dynamic_padding"
1099 ]
1100 )]
1101 #[inline]
1102 pub fn bytes(r: &Self) -> &[u8] {
1103 // SAFETY: We don't call any methods on `b` other than those provided by
1104 // `ByteSlice`.
1105 unsafe { r.as_byte_slice().deref() }
1106 }
1107}
1108
1109impl<B, T> Ref<B, T>
1110where
1111 B: ByteSliceMut,
1112 T: ?Sized,
1113{
1114 /// Gets the underlying bytes mutably.
1115 ///
1116 /// Note: this is an associated function, which means that you have to call
1117 /// it as `Ref::bytes_mut(r)` instead of `r.bytes_mut()`. This is so that
1118 /// there is no conflict with a method on the inner type.
1119 ///
1120 #[doc = codegen_section!(
1121 header = "h5",
1122 bench = "ref_type_bytes_mut",
1123 format = "coco",
1124 arity = 3,
1125 [
1126 open
1127 @index 1
1128 @title "Sized"
1129 @variant "static_size"
1130 ],
1131 [
1132 @index 2
1133 @title "Unsized"
1134 @variant "dynamic_size"
1135 ],
1136 [
1137 @index 3
1138 @title "Dynamically Padded"
1139 @variant "dynamic_padding"
1140 ]
1141 )]
1142 #[inline]
1143 pub fn bytes_mut(r: &mut Self) -> &mut [u8] {
1144 // SAFETY: We don't call any methods on `b` other than those provided by
1145 // `ByteSliceMut`.
1146 unsafe { r.as_byte_slice_mut().deref_mut() }
1147 }
1148}
1149
1150impl<B, T> Ref<B, T>
1151where
1152 B: ByteSlice,
1153 T: FromBytes,
1154{
1155 /// Reads a copy of `T`.
1156 ///
1157 /// Note: this is an associated function, which means that you have to call
1158 /// it as `Ref::read(r)` instead of `r.read()`. This is so that there is no
1159 /// conflict with a method on the inner type.
1160 ///
1161 #[doc = codegen_section!(
1162 header = "h5",
1163 bench = "ref_type_read_static_size",
1164 format = "coco_static_size",
1165 )]
1166 #[must_use = "has no side effects"]
1167 #[inline]
1168 pub fn read(r: &Self) -> T {
1169 // SAFETY: We don't call any methods on `b` other than those provided by
1170 // `ByteSlice`.
1171 let b = unsafe { r.as_byte_slice() };
1172
1173 // SAFETY: By postcondition on `as_byte_slice`, we know that `b` is a
1174 // valid size and alignment for `T`. By safety invariant on `ByteSlice`,
1175 // we know that this is preserved via `.deref()`. Because `T:
1176 // FromBytes`, it is sound to interpret these bytes as a `T`.
1177 unsafe { ptr::read(b.deref().as_ptr().cast::<T>()) }
1178 }
1179}
1180
1181impl<B, T> Ref<B, T>
1182where
1183 B: ByteSliceMut,
1184 T: IntoBytes,
1185{
1186 /// Writes the bytes of `t` and then forgets `t`.
1187 ///
1188 /// Note: this is an associated function, which means that you have to call
1189 /// it as `Ref::write(r, t)` instead of `r.write(t)`. This is so that there
1190 /// is no conflict with a method on the inner type.
1191 ///
1192 #[doc = codegen_section!(
1193 header = "h5",
1194 bench = "ref_type_write_static_size",
1195 format = "coco_static_size",
1196 )]
1197 #[inline]
1198 pub fn write(r: &mut Self, t: T) {
1199 // SAFETY: We don't call any methods on `b` other than those provided by
1200 // `ByteSliceMut`.
1201 let b = unsafe { r.as_byte_slice_mut() };
1202
1203 // SAFETY: By postcondition on `as_byte_slice_mut`, we know that `b` is a
1204 // valid size and alignment for `T`. By safety invariant on
1205 // `ByteSlice`, we know that this is preserved via `.deref()`. Writing
1206 // `t` to the buffer will allow all of the bytes of `t` to be accessed
1207 // as a `[u8]`, but because `T: IntoBytes`, we know that this is sound.
1208 unsafe { ptr::write(b.deref_mut().as_mut_ptr().cast::<T>(), t) }
1209 }
1210}
1211
1212impl<B, T> Deref for Ref<B, T>
1213where
1214 B: ByteSlice,
1215 T: FromBytes + KnownLayout + Immutable + ?Sized,
1216{
1217 type Target = T;
1218
1219 /// Dereferences the value.
1220 ///
1221 #[doc = codegen_section!(
1222 header = "h5",
1223 bench = "ref_type_deref",
1224 format = "coco",
1225 arity = 3,
1226 [
1227 open
1228 @index 1
1229 @title "Sized"
1230 @variant "static_size"
1231 ],
1232 [
1233 @index 2
1234 @title "Unsized"
1235 @variant "dynamic_size"
1236 ],
1237 [
1238 @index 3
1239 @title "Dynamically Padded"
1240 @variant "dynamic_padding"
1241 ]
1242 )]
1243 #[inline]
1244 fn deref(&self) -> &T {
1245 // Presumably unreachable, since we've guarded each constructor of `Ref`.
1246 static_assert_dst_is_not_zst!(T);
1247
1248 let metadata = self.pointer_metadata();
1249
1250 // SAFETY: We don't call any methods on `b` other than those provided by
1251 // `ByteSlice`.
1252 let b = unsafe { self.as_byte_slice() };
1253 let b = b.deref();
1254
1255 if let crate::layout::SizeInfo::Sized { .. } = T::LAYOUT.size_info {
1256 let ptr = Ptr::from_ref(b);
1257 // SAFETY: We just checked that `T: Sized`. By invariant on `r`,
1258 // `b`'s size is equal to `size_of::<T>()`.
1259 let ptr = unsafe { cast_for_sized::<T, _, _, _>(ptr) };
1260
1261 // SAFETY: None of the preceding transformations modifies the
1262 // address of the pointer, and by invariant on `r`, we know that it
1263 // is validly-aligned.
1264 let ptr = unsafe { ptr.assume_alignment::<Aligned>() };
1265 return ptr.as_ref();
1266 }
1267
1268 // PANICS: By postcondition on `as_byte_slice`, `b` is aligned for `T`,
1269 // and its size is exactly the size encoded by `metadata`. By invariant
1270 // on `ByteSlice`, these are preserved through `.deref()`, so this
1271 // `unwrap` will not panic.
1272 let ptr = Ptr::from_ref(b)
1273 .try_cast_into_no_leftover::<T, BecauseImmutable>(Some(metadata))
1274 .expect("zerocopy internal error: Deref::deref should be infallible");
1275 let ptr = ptr.recall_validity();
1276 ptr.as_ref()
1277 }
1278}
1279
1280impl<B, T> DerefMut for Ref<B, T>
1281where
1282 B: ByteSliceMut,
1283 // FIXME(#251): We can't remove `Immutable` here because it's required by
1284 // the impl of `Deref`, which is a super-trait of `DerefMut`. Maybe we can
1285 // add a separate inherent method for this?
1286 T: FromBytes + IntoBytes + KnownLayout + Immutable + ?Sized,
1287{
1288 /// Mutably dereferences the value.
1289 ///
1290 #[doc = codegen_section!(
1291 header = "h5",
1292 bench = "ref_type_deref_mut",
1293 format = "coco",
1294 arity = 2,
1295 [
1296 open
1297 @index 1
1298 @title "Sized"
1299 @variant "static_size"
1300 ],
1301 [
1302 @index 2
1303 @title "Unsized"
1304 @variant "dynamic_size"
1305 ]
1306 )]
1307 #[inline]
1308 fn deref_mut(&mut self) -> &mut T {
1309 // Presumably unreachable, since we've guarded each constructor of `Ref`.
1310 static_assert_dst_is_not_zst!(T);
1311
1312 let metadata = self.pointer_metadata();
1313
1314 // SAFETY: We don't call any methods on `b` other than those provided by
1315 // `ByteSliceMut`.
1316 let b = unsafe { self.as_byte_slice_mut() };
1317 let b = b.deref_mut();
1318
1319 if let crate::layout::SizeInfo::Sized { .. } = T::LAYOUT.size_info {
1320 let ptr = Ptr::from_mut(b);
1321 // SAFETY: We just checked that `T: Sized`. By invariant on `r`,
1322 // `b`'s size is equal to `size_of::<T>()`.
1323 let ptr = unsafe {
1324 cast_for_sized::<
1325 T,
1326 _,
1327 (BecauseRead, BecauseExclusive),
1328 (BecauseMutationCompatible, BecauseSharedCompatible),
1329 >(ptr)
1330 };
1331
1332 // SAFETY: None of the preceding transformations modifies the
1333 // address of the pointer, and by invariant on `r`, we know that it
1334 // is validly-aligned.
1335 let ptr = unsafe { ptr.assume_alignment::<Aligned>() };
1336 return ptr.as_mut();
1337 }
1338
1339 // PANICS: By postcondition on `as_byte_slice_mut`, `b` is aligned for
1340 // `T`, and its size is exactly the size encoded by `metadata`. By
1341 // invariant on `ByteSlice`, these are preserved through `.deref_mut()`,
1342 // so this `unwrap` will not panic.
1343 let ptr = Ptr::from_mut(b)
1344 .try_cast_into_no_leftover::<T, BecauseExclusive>(Some(metadata))
1345 .expect("zerocopy internal error: DerefMut::deref_mut should be infallible");
1346 let ptr = ptr.recall_validity::<_, (_, (_, BecauseExclusive))>();
1347 ptr.as_mut()
1348 }
1349}
1350
1351impl<T, B> Display for Ref<B, T>
1352where
1353 B: ByteSlice,
1354 T: FromBytes + Display + KnownLayout + Immutable + ?Sized,
1355{
1356 #[inline]
1357 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
1358 let inner: &T = self;
1359 inner.fmt(fmt)
1360 }
1361}
1362
1363impl<T, B> Debug for Ref<B, T>
1364where
1365 B: ByteSlice,
1366 T: FromBytes + Debug + KnownLayout + Immutable + ?Sized,
1367{
1368 #[inline]
1369 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
1370 let inner: &T = self;
1371 fmt.debug_tuple("Ref").field(&inner).finish()
1372 }
1373}
1374
1375impl<T, B> Eq for Ref<B, T>
1376where
1377 B: ByteSlice,
1378 T: FromBytes + Eq + KnownLayout + Immutable + ?Sized,
1379{
1380}
1381
1382impl<T, B> PartialEq for Ref<B, T>
1383where
1384 B: ByteSlice,
1385 T: FromBytes + PartialEq + KnownLayout + Immutable + ?Sized,
1386{
1387 #[inline]
1388 fn eq(&self, other: &Self) -> bool {
1389 self.deref().eq(other.deref())
1390 }
1391}
1392
1393impl<T, B> Ord for Ref<B, T>
1394where
1395 B: ByteSlice,
1396 T: FromBytes + Ord + KnownLayout + Immutable + ?Sized,
1397{
1398 #[inline]
1399 fn cmp(&self, other: &Self) -> Ordering {
1400 let inner: &T = self;
1401 let other_inner: &T = other;
1402 inner.cmp(other_inner)
1403 }
1404}
1405
1406impl<T, B> PartialOrd for Ref<B, T>
1407where
1408 B: ByteSlice,
1409 T: FromBytes + PartialOrd + KnownLayout + Immutable + ?Sized,
1410{
1411 #[inline]
1412 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1413 let inner: &T = self;
1414 let other_inner: &T = other;
1415 inner.partial_cmp(other_inner)
1416 }
1417}
1418
1419/// # Safety
1420///
1421/// `T: Sized` and `ptr`'s referent must have size `size_of::<T>()`.
1422#[inline(always)]
1423unsafe fn cast_for_sized<'a, T, A, R, S>(
1424 ptr: Ptr<'a, [u8], (A, Aligned, Safe)>,
1425) -> Ptr<'a, T, (A, Unaligned, Safe)>
1426where
1427 T: FromBytes + KnownLayout + ?Sized,
1428 A: crate::invariant::Aliasing,
1429 [u8]: MutationCompatible<T, A, Initialized, Initialized, R>,
1430 T: TransmuteFromPtr<T, A, Initialized, Safe, crate::pointer::cast::IdCast, S>,
1431{
1432 use crate::pointer::cast::{Cast, Project};
1433
1434 enum CastForSized {}
1435
1436 // SAFETY: `CastForSized` is only used below with the input `ptr`, which the
1437 // caller promises has size `size_of::<T>()`. Thus, the referent produced in
1438 // this cast has the same size as `ptr`'s referent. All operations preserve
1439 // provenance.
1440 unsafe impl<T: ?Sized + KnownLayout> Project<[u8], T> for CastForSized {
1441 #[inline(always)]
1442 fn project(src: PtrInner<'_, [u8]>) -> *mut T {
1443 T::raw_from_ptr_len(
1444 src.as_non_null().cast(),
1445 <T::PointerMetadata as crate::PointerMetadata>::from_elem_count(0),
1446 )
1447 .as_ptr()
1448 }
1449 }
1450
1451 // SAFETY: The `Project::project` impl preserves referent address.
1452 unsafe impl<T: ?Sized + KnownLayout> Cast<[u8], T> for CastForSized {}
1453
1454 ptr.recall_validity::<Initialized, (_, (_, _))>()
1455 .cast::<_, CastForSized, _>()
1456 .recall_validity::<Safe, _>()
1457}
1458
1459#[cfg(test)]
1460#[allow(clippy::assertions_on_result_states)]
1461mod tests {
1462 use core::convert::TryInto as _;
1463
1464 use super::*;
1465 use crate::util::testutil::*;
1466
1467 #[test]
1468 fn test_mut_slice_into_ref() {
1469 // Prior to #1260/#1299, calling `into_ref` on a `&mut [u8]`-backed
1470 // `Ref` was not supported.
1471 let mut buf = [0u8];
1472 let r = Ref::<&mut [u8], u8>::from_bytes(&mut buf).unwrap();
1473 assert_eq!(Ref::into_ref(r), &0);
1474 }
1475
1476 #[test]
1477 fn test_address() {
1478 // Test that the `Deref` and `DerefMut` implementations return a
1479 // reference which points to the right region of memory.
1480
1481 let buf = [0];
1482 let r = Ref::<_, u8>::from_bytes(&buf[..]).unwrap();
1483 let buf_ptr = buf.as_ptr();
1484 let deref_ptr: *const u8 = r.deref();
1485 assert_eq!(buf_ptr, deref_ptr);
1486
1487 let buf = [0];
1488 let r = Ref::<_, [u8]>::from_bytes(&buf[..]).unwrap();
1489 let buf_ptr = buf.as_ptr();
1490 let deref_ptr = r.deref().as_ptr();
1491 assert_eq!(buf_ptr, deref_ptr);
1492 }
1493
1494 #[test]
1495 #[allow(clippy::clone_on_copy)] // Exercise `Ref`'s manual `Clone` impl.
1496 fn test_with_elems_preserves_ambiguous_metadata() {
1497 #[derive(FromBytes, Immutable, KnownLayout)]
1498 #[repr(C, align(8))]
1499 struct Frame {
1500 header: [u8; 8],
1501 body: [u8],
1502 }
1503
1504 #[derive(FromBytes, Immutable, KnownLayout)]
1505 #[repr(C, align(8))]
1506 struct OddHeader {
1507 header: [u8; 7],
1508 body: [u8],
1509 }
1510
1511 // Dynamic trailing padding makes these pairs of distinct element
1512 // counts produce the same total byte size. Thus, the byte length alone
1513 // cannot recover the count supplied to a `*_with_elems` constructor.
1514 assert_eq!(Frame::size_for_metadata(1), Some(16));
1515 assert_eq!(Frame::size_for_metadata(8), Some(16));
1516 assert_eq!(OddHeader::size_for_metadata(0), Some(8));
1517 assert_eq!(OddHeader::size_for_metadata(1), Some(8));
1518
1519 let bytes = Align::<[u8; 32], AU64>::default();
1520
1521 let whole = Ref::<_, Frame>::from_bytes_with_elems(&bytes.t[..16], 1).unwrap();
1522 assert_eq!(whole.body.len(), 1);
1523 assert_eq!(Ref::bytes(&whole).len(), 16);
1524 assert_eq!(whole.clone().body.len(), 1);
1525 let copied = whole;
1526 assert_eq!(copied.body.len(), 1);
1527 assert_eq!(Ref::into_ref(whole).body.len(), 1);
1528
1529 let (prefix, rest) = Ref::<_, Frame>::from_prefix_with_elems(&bytes.t[..], 1).unwrap();
1530 assert_eq!(prefix.body.len(), 1);
1531 assert_eq!(rest.len(), 16);
1532
1533 let (before, suffix) = Ref::<_, Frame>::from_suffix_with_elems(&bytes.t[..24], 1).unwrap();
1534 assert_eq!(before.len(), 8);
1535 assert_eq!(suffix.body.len(), 1);
1536
1537 // Zero is real metadata, not a sentinel for "infer from the bytes".
1538 let empty = Ref::<_, OddHeader>::from_bytes_with_elems(&bytes.t[..8], 0).unwrap();
1539 assert!(empty.body.is_empty());
1540 assert!(Ref::into_ref(empty).body.is_empty());
1541
1542 // The implicit constructors still choose the largest fitting count,
1543 // and retain the metadata selected during their validating cast.
1544 let inferred = Ref::<_, Frame>::from_bytes(&bytes.t[..16]).unwrap();
1545 assert_eq!(inferred.body.len(), 8);
1546 let (inferred, rest) = Ref::<_, Frame>::from_prefix(&bytes.t[..16]).unwrap();
1547 assert_eq!(inferred.body.len(), 8);
1548 assert!(rest.is_empty());
1549 let (before, inferred) = Ref::<_, Frame>::from_suffix(&bytes.t[..16]).unwrap();
1550 assert!(before.is_empty());
1551 assert_eq!(inferred.body.len(), 8);
1552 }
1553
1554 // Verify that values written to a `Ref` are properly shared between the
1555 // typed and untyped representations, that reads via `deref` and `read`
1556 // behave the same, and that writes via `deref_mut` and `write` behave the
1557 // same.
1558 fn test_new_helper(mut r: Ref<&mut [u8], AU64>) {
1559 // assert that the value starts at 0
1560 assert_eq!(*r, AU64(0));
1561 assert_eq!(Ref::read(&r), AU64(0));
1562
1563 // Assert that values written to the typed value are reflected in the
1564 // byte slice.
1565 const VAL1: AU64 = AU64(0xFF00FF00FF00FF00);
1566 *r = VAL1;
1567 assert_eq!(Ref::bytes(&r), &VAL1.to_bytes());
1568 *r = AU64(0);
1569 Ref::write(&mut r, VAL1);
1570 assert_eq!(Ref::bytes(&r), &VAL1.to_bytes());
1571
1572 // Assert that values written to the byte slice are reflected in the
1573 // typed value.
1574 const VAL2: AU64 = AU64(!VAL1.0); // different from `VAL1`
1575 Ref::bytes_mut(&mut r).copy_from_slice(&VAL2.to_bytes()[..]);
1576 assert_eq!(*r, VAL2);
1577 assert_eq!(Ref::read(&r), VAL2);
1578 }
1579
1580 // Verify that values written to a `Ref` are properly shared between the
1581 // typed and untyped representations; pass a value with `typed_len` `AU64`s
1582 // backed by an array of `typed_len * 8` bytes.
1583 fn test_new_helper_slice(mut r: Ref<&mut [u8], [AU64]>, typed_len: usize) {
1584 // Assert that the value starts out zeroed.
1585 assert_eq!(&*r, vec![AU64(0); typed_len].as_slice());
1586
1587 // Check the backing storage is the exact same slice.
1588 let untyped_len = typed_len * 8;
1589 assert_eq!(Ref::bytes(&r).len(), untyped_len);
1590 assert_eq!(Ref::bytes(&r).as_ptr(), r.as_ptr().cast::<u8>());
1591
1592 // Assert that values written to the typed value are reflected in the
1593 // byte slice.
1594 const VAL1: AU64 = AU64(0xFF00FF00FF00FF00);
1595 for typed in &mut *r {
1596 *typed = VAL1;
1597 }
1598 assert_eq!(Ref::bytes(&r), VAL1.0.to_ne_bytes().repeat(typed_len).as_slice());
1599
1600 // Assert that values written to the byte slice are reflected in the
1601 // typed value.
1602 const VAL2: AU64 = AU64(!VAL1.0); // different from VAL1
1603 Ref::bytes_mut(&mut r).copy_from_slice(&VAL2.0.to_ne_bytes().repeat(typed_len));
1604 assert!(r.iter().copied().all(|x| x == VAL2));
1605 }
1606
1607 #[test]
1608 fn test_new_aligned_sized() {
1609 // Test that a properly-aligned, properly-sized buffer works for new,
1610 // new_from_prefix, and new_from_suffix, and that new_from_prefix and
1611 // new_from_suffix return empty slices. Test that a properly-aligned
1612 // buffer whose length is a multiple of the element size works for
1613 // new_slice.
1614
1615 // A buffer with an alignment of 8.
1616 let mut buf = Align::<[u8; 8], AU64>::default();
1617 // `buf.t` should be aligned to 8, so this should always succeed.
1618 test_new_helper(Ref::<_, AU64>::from_bytes(&mut buf.t[..]).unwrap());
1619 {
1620 // In a block so that `r` and `suffix` don't live too long.
1621 buf.set_default();
1622 let (r, suffix) = Ref::<_, AU64>::from_prefix(&mut buf.t[..]).unwrap();
1623 assert!(suffix.is_empty());
1624 test_new_helper(r);
1625 }
1626 {
1627 buf.set_default();
1628 let (prefix, r) = Ref::<_, AU64>::from_suffix(&mut buf.t[..]).unwrap();
1629 assert!(prefix.is_empty());
1630 test_new_helper(r);
1631 }
1632
1633 // A buffer with alignment 8 and length 24. We choose this length very
1634 // intentionally: if we instead used length 16, then the prefix and
1635 // suffix lengths would be identical. In the past, we used length 16,
1636 // which resulted in this test failing to discover the bug uncovered in
1637 // #506.
1638 let mut buf = Align::<[u8; 24], AU64>::default();
1639 // `buf.t` should be aligned to 8 and have a length which is a multiple
1640 // of `size_of::<AU64>()`, so this should always succeed.
1641 test_new_helper_slice(Ref::<_, [AU64]>::from_bytes(&mut buf.t[..]).unwrap(), 3);
1642 buf.set_default();
1643 let r = Ref::<_, [AU64]>::from_bytes_with_elems(&mut buf.t[..], 3).unwrap();
1644 test_new_helper_slice(r, 3);
1645
1646 let ascending: [u8; 24] = (0..24).collect::<Vec<_>>().try_into().unwrap();
1647 // 16 ascending bytes followed by 8 zeros.
1648 let mut ascending_prefix = ascending;
1649 ascending_prefix[16..].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]);
1650 // 8 zeros followed by 16 ascending bytes.
1651 let mut ascending_suffix = ascending;
1652 ascending_suffix[..8].copy_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]);
1653 {
1654 buf.t = ascending_suffix;
1655 let (r, suffix) = Ref::<_, [AU64]>::from_prefix_with_elems(&mut buf.t[..], 1).unwrap();
1656 assert_eq!(suffix, &ascending[8..]);
1657 test_new_helper_slice(r, 1);
1658 }
1659 {
1660 buf.t = ascending_prefix;
1661 let (prefix, r) = Ref::<_, [AU64]>::from_suffix_with_elems(&mut buf.t[..], 1).unwrap();
1662 assert_eq!(prefix, &ascending[..16]);
1663 test_new_helper_slice(r, 1);
1664 }
1665 }
1666
1667 #[test]
1668 fn test_new_oversized() {
1669 // Test that a properly-aligned, overly-sized buffer works for
1670 // `new_from_prefix` and `new_from_suffix`, and that they return the
1671 // remainder and prefix of the slice respectively.
1672
1673 let mut buf = Align::<[u8; 16], AU64>::default();
1674 {
1675 // In a block so that `r` and `suffix` don't live too long. `buf.t`
1676 // should be aligned to 8, so this should always succeed.
1677 let (r, suffix) = Ref::<_, AU64>::from_prefix(&mut buf.t[..]).unwrap();
1678 assert_eq!(suffix.len(), 8);
1679 test_new_helper(r);
1680 }
1681 {
1682 buf.set_default();
1683 // `buf.t` should be aligned to 8, so this should always succeed.
1684 let (prefix, r) = Ref::<_, AU64>::from_suffix(&mut buf.t[..]).unwrap();
1685 assert_eq!(prefix.len(), 8);
1686 test_new_helper(r);
1687 }
1688 }
1689
1690 #[test]
1691 #[allow(clippy::cognitive_complexity)]
1692 fn test_new_error() {
1693 // Fail because the buffer is too large.
1694
1695 // A buffer with an alignment of 8.
1696 let buf = Align::<[u8; 16], AU64>::default();
1697 // `buf.t` should be aligned to 8, so only the length check should fail.
1698 assert!(Ref::<_, AU64>::from_bytes(&buf.t[..]).is_err());
1699
1700 // Fail because the buffer is too small.
1701
1702 // A buffer with an alignment of 8.
1703 let buf = Align::<[u8; 4], AU64>::default();
1704 // `buf.t` should be aligned to 8, so only the length check should fail.
1705 assert!(Ref::<_, AU64>::from_bytes(&buf.t[..]).is_err());
1706 assert!(Ref::<_, AU64>::from_prefix(&buf.t[..]).is_err());
1707 assert!(Ref::<_, AU64>::from_suffix(&buf.t[..]).is_err());
1708
1709 // Fail because the length is not a multiple of the element size.
1710
1711 let buf = Align::<[u8; 12], AU64>::default();
1712 // `buf.t` has length 12, but element size is 8.
1713 assert!(Ref::<_, [AU64]>::from_bytes(&buf.t[..]).is_err());
1714
1715 // Fail because the buffer is too short.
1716 let buf = Align::<[u8; 12], AU64>::default();
1717 // `buf.t` has length 12, but the element size is 8 (and we're expecting
1718 // two of them). For each function, we test with a length that would
1719 // cause the size to overflow `usize`, and with a normal length that
1720 // will fail thanks to the buffer being too short; these are different
1721 // error paths, and while the error types are the same, the distinction
1722 // shows up in code coverage metrics.
1723 let n = (usize::MAX / mem::size_of::<AU64>()) + 1;
1724 assert!(Ref::<_, [AU64]>::from_bytes_with_elems(&buf.t[..], n).is_err());
1725 assert!(Ref::<_, [AU64]>::from_bytes_with_elems(&buf.t[..], 2).is_err());
1726 assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[..], n).is_err());
1727 assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[..], 2).is_err());
1728 assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[..], n).is_err());
1729 assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[..], 2).is_err());
1730
1731 // Fail because the alignment is insufficient.
1732
1733 // A buffer with an alignment of 8. An odd buffer size is chosen so that
1734 // the last byte of the buffer has odd alignment.
1735 let buf = Align::<[u8; 13], AU64>::default();
1736 // Slicing from 1, we get a buffer with size 12 (so the length check
1737 // should succeed) but an alignment of only 1, which is insufficient.
1738 assert!(Ref::<_, AU64>::from_bytes(&buf.t[1..]).is_err());
1739 assert!(Ref::<_, AU64>::from_prefix(&buf.t[1..]).is_err());
1740 assert!(Ref::<_, [AU64]>::from_bytes(&buf.t[1..]).is_err());
1741 assert!(Ref::<_, [AU64]>::from_bytes_with_elems(&buf.t[1..], 1).is_err());
1742 assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[1..], 1).is_err());
1743 assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[1..], 1).is_err());
1744 // Slicing is unnecessary here because `new_from_suffix` uses the suffix
1745 // of the slice, which has odd alignment.
1746 assert!(Ref::<_, AU64>::from_suffix(&buf.t[..]).is_err());
1747
1748 // Fail due to arithmetic overflow.
1749
1750 let buf = Align::<[u8; 16], AU64>::default();
1751 let unreasonable_len = usize::MAX / mem::size_of::<AU64>() + 1;
1752 assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[..], unreasonable_len).is_err());
1753 assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[..], unreasonable_len).is_err());
1754 }
1755
1756 #[test]
1757 #[allow(unstable_name_collisions)]
1758 #[allow(clippy::as_conversions)]
1759 fn test_into_ref_mut() {
1760 #[allow(unused)]
1761 use crate::util::AsAddress as _;
1762
1763 let mut buf = Align::<[u8; 8], u64>::default();
1764 let r = Ref::<_, u64>::from_bytes(&buf.t[..]).unwrap();
1765 let rf = Ref::into_ref(r);
1766 assert_eq!(rf, &0u64);
1767 let buf_addr = (&buf.t as *const [u8; 8]).addr();
1768 assert_eq!((rf as *const u64).addr(), buf_addr);
1769
1770 let r = Ref::<_, u64>::from_bytes(&mut buf.t[..]).unwrap();
1771 let rf = Ref::into_mut(r);
1772 assert_eq!(rf, &mut 0u64);
1773 assert_eq!((rf as *mut u64).addr(), buf_addr);
1774
1775 *rf = u64::MAX;
1776 assert_eq!(buf.t, [0xFF; 8]);
1777
1778 // Exercise the unsized `into_mut` route, which must use the metadata
1779 // retained by the constructor rather than infer fresh metadata.
1780 let mut buf = Align::<[u8; 8], u16>::default();
1781 let r = Ref::<_, [u16]>::from_bytes_with_elems(&mut buf.t[..], 4).unwrap();
1782 let rf = Ref::into_mut(r);
1783 assert_eq!(rf.len(), 4);
1784 }
1785
1786 #[test]
1787 fn test_display_debug() {
1788 let buf = Align::<[u8; 8], u64>::default();
1789 let r = Ref::<_, u64>::from_bytes(&buf.t[..]).unwrap();
1790 assert_eq!(format!("{}", r), "0");
1791 assert_eq!(format!("{:?}", r), "Ref(0)");
1792
1793 let buf = Align::<[u8; 8], u64>::default();
1794 let r = Ref::<_, [u64]>::from_bytes(&buf.t[..]).unwrap();
1795 assert_eq!(format!("{:?}", r), "Ref([0])");
1796 }
1797
1798 #[test]
1799 fn test_eq() {
1800 let buf1 = 0_u64;
1801 let r1 = Ref::<_, u64>::from_bytes(buf1.as_bytes()).unwrap();
1802 let buf2 = 0_u64;
1803 let r2 = Ref::<_, u64>::from_bytes(buf2.as_bytes()).unwrap();
1804 assert_eq!(r1, r2);
1805 }
1806
1807 #[test]
1808 fn test_ne() {
1809 let buf1 = 0_u64;
1810 let r1 = Ref::<_, u64>::from_bytes(buf1.as_bytes()).unwrap();
1811 let buf2 = 1_u64;
1812 let r2 = Ref::<_, u64>::from_bytes(buf2.as_bytes()).unwrap();
1813 assert_ne!(r1, r2);
1814 }
1815
1816 #[test]
1817 fn test_ord() {
1818 let buf1 = 0_u64;
1819 let r1 = Ref::<_, u64>::from_bytes(buf1.as_bytes()).unwrap();
1820 let buf2 = 1_u64;
1821 let r2 = Ref::<_, u64>::from_bytes(buf2.as_bytes()).unwrap();
1822 assert!(r1 < r2);
1823 assert_eq!(PartialOrd::partial_cmp(&r1, &r2), Some(Ordering::Less));
1824 assert_eq!(Ord::cmp(&r1, &r2), Ordering::Less);
1825 }
1826}
1827
1828#[cfg(all(test, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS))]
1829mod benches {
1830 use test::{self, Bencher};
1831
1832 use super::*;
1833 use crate::util::testutil::*;
1834
1835 #[bench]
1836 fn bench_from_bytes_sized(b: &mut Bencher) {
1837 let buf = Align::<[u8; 8], AU64>::default();
1838 // `buf.t` should be aligned to 8, so this should always succeed.
1839 let bytes = &buf.t[..];
1840 b.iter(|| test::black_box(Ref::<_, AU64>::from_bytes(test::black_box(bytes)).unwrap()));
1841 }
1842
1843 #[bench]
1844 fn bench_into_ref_sized(b: &mut Bencher) {
1845 let buf = Align::<[u8; 8], AU64>::default();
1846 let bytes = &buf.t[..];
1847 let r = Ref::<_, AU64>::from_bytes(bytes).unwrap();
1848 b.iter(|| test::black_box(Ref::into_ref(test::black_box(r))));
1849 }
1850
1851 #[bench]
1852 fn bench_into_mut_sized(b: &mut Bencher) {
1853 let mut buf = Align::<[u8; 8], AU64>::default();
1854 let buf = &mut buf.t[..];
1855 let _ = Ref::<_, AU64>::from_bytes(&mut *buf).unwrap();
1856 b.iter(move || {
1857 // SAFETY: The preceding `from_bytes` succeeded, and so we know that
1858 // `buf` is validly aligned and has the `size_of::<AU64>()` byte
1859 // length required by `new_sized_unchecked` [1].
1860 //
1861 // [1] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.size_of.html:
1862 //
1863 // Returns the size of a type in bytes.
1864 let r = unsafe { Ref::<&mut [u8], AU64>::new_sized_unchecked(&mut *buf) };
1865 test::black_box(Ref::into_mut(test::black_box(r)));
1866 });
1867 }
1868
1869 #[bench]
1870 fn bench_deref_sized(b: &mut Bencher) {
1871 let buf = Align::<[u8; 8], AU64>::default();
1872 let bytes = &buf.t[..];
1873 let r = Ref::<_, AU64>::from_bytes(bytes).unwrap();
1874 b.iter(|| {
1875 let temp = test::black_box(r);
1876 test::black_box(temp.deref());
1877 });
1878 }
1879
1880 #[bench]
1881 fn bench_deref_mut_sized(b: &mut Bencher) {
1882 let mut buf = Align::<[u8; 8], AU64>::default();
1883 let buf = &mut buf.t[..];
1884 let _ = Ref::<_, AU64>::from_bytes(&mut *buf).unwrap();
1885 b.iter(|| {
1886 // SAFETY: The preceding `from_bytes` succeeded, and so we know that
1887 // `buf` is validly aligned and has the `size_of::<AU64>()` byte
1888 // length required by `new_sized_unchecked` [1].
1889 //
1890 // [1] Per https://doc.rust-lang.org/1.56.0/core/mem/fn.size_of.html:
1891 //
1892 // Returns the size of a type in bytes.
1893 let r = unsafe { Ref::<&mut [u8], AU64>::new_sized_unchecked(&mut *buf) };
1894 let mut temp = test::black_box(r);
1895 test::black_box(temp.deref_mut());
1896 });
1897 }
1898}