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