Coverage Report

Created: 2026-05-30 07:32

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