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