Coverage Report

Created: 2024-09-06 06:26

/rust/registry/src/index.crates.io-6f17d22bba15001f/zerocopy-0.7.32/src/util.rs
Line
Count
Source
1
// Copyright 2023 The Fuchsia Authors
2
//
3
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6
// This file may not be copied, modified, or distributed except according to
7
// those terms.
8
9
#[path = "third_party/rust/layout.rs"]
10
pub(crate) mod core_layout;
11
12
use core::{mem, num::NonZeroUsize};
13
14
pub(crate) mod ptr {
15
    use core::{
16
        fmt::{Debug, Formatter},
17
        marker::PhantomData,
18
        ptr::NonNull,
19
    };
20
21
    use crate::{util::AsAddress, KnownLayout, _CastType};
22
23
    /// A raw pointer with more restrictions.
24
    ///
25
    /// `Ptr<T>` is similar to `NonNull<T>`, but it is more restrictive in the
26
    /// following ways:
27
    /// - It must derive from a valid allocation
28
    /// - It must reference a byte range which is contained inside the
29
    ///   allocation from which it derives
30
    ///   - As a consequence, the byte range it references must have a size
31
    ///     which does not overflow `isize`
32
    /// - It must satisfy `T`'s alignment requirement
33
    ///
34
    /// Thanks to these restrictions, it is easier to prove the soundness of
35
    /// some operations using `Ptr`s.
36
    ///
37
    /// `Ptr<'a, T>` is [covariant] in `'a` and `T`.
38
    ///
39
    /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
40
    pub struct Ptr<'a, T: 'a + ?Sized> {
41
        // INVARIANTS:
42
        // 1. `ptr` is derived from some valid Rust allocation, `A`
43
        // 2. `ptr` has the same provenance as `A`
44
        // 3. `ptr` addresses a byte range which is entirely contained in `A`
45
        // 4. `ptr` addresses a byte range whose length fits in an `isize`
46
        // 5. `ptr` addresses a byte range which does not wrap around the address
47
        //     space
48
        // 6. `ptr` is validly-aligned for `T`
49
        // 7. `A` is guaranteed to live for at least `'a`
50
        // 8. `T: 'a`
51
        ptr: NonNull<T>,
52
        _lifetime: PhantomData<&'a ()>,
53
    }
54
55
    impl<'a, T: ?Sized> Copy for Ptr<'a, T> {}
56
    impl<'a, T: ?Sized> Clone for Ptr<'a, T> {
57
        #[inline]
58
        fn clone(&self) -> Self {
59
            *self
60
        }
61
    }
62
63
    impl<'a, T: ?Sized> Ptr<'a, T> {
64
        /// Returns a shared reference to the value.
65
        ///
66
        /// # Safety
67
        ///
68
        /// For the duration of `'a`:
69
        /// - The referenced memory must contain a validly-initialized `T` for
70
        ///   the duration of `'a`.
71
        /// - The referenced memory must not also be referenced by any mutable
72
        ///   references.
73
        /// - The referenced memory must not be mutated, even via an
74
        ///   [`UnsafeCell`].
75
        /// - There must not exist any references to the same memory region
76
        ///   which contain `UnsafeCell`s at byte ranges which are not identical
77
        ///   to the byte ranges at which `T` contains `UnsafeCell`s.
78
        ///
79
        /// [`UnsafeCell`]: core::cell::UnsafeCell
80
        // TODO(#429): The safety requirements are likely overly-restrictive.
81
        // Notably, mutation via `UnsafeCell`s is probably fine. Once the rules
82
        // are more clearly defined, we should relax the safety requirements.
83
        // For an example of why this is subtle, see:
84
        // https://github.com/rust-lang/unsafe-code-guidelines/issues/463#issuecomment-1736771593
85
        #[allow(unused)]
86
        pub(crate) unsafe fn as_ref(&self) -> &'a T {
87
            // SAFETY:
88
            // - By invariant, `self.ptr` is properly-aligned for `T`.
89
            // - By invariant, `self.ptr` is "dereferenceable" in that it points
90
            //   to a single allocation.
91
            // - By invariant, the allocation is live for `'a`.
92
            // - The caller promises that no mutable references exist to this
93
            //   region during `'a`.
94
            // - The caller promises that `UnsafeCell`s match exactly.
95
            // - The caller promises that no mutation will happen during `'a`,
96
            //   even via `UnsafeCell`s.
97
            // - The caller promises that the memory region contains a
98
            //   validly-intialized `T`.
99
            unsafe { self.ptr.as_ref() }
100
        }
101
102
        /// Casts to a different (unsized) target type.
103
        ///
104
        /// # Safety
105
        ///
106
        /// The caller promises that
107
        /// - `cast(p)` is implemented exactly as follows: `|p: *mut T| p as
108
        ///   *mut U`.
109
        /// - The size of the object referenced by the resulting pointer is less
110
        ///   than or equal to the size of the object referenced by `self`.
111
        /// - The alignment of `U` is less than or equal to the alignment of
112
        ///   `T`.
113
        pub(crate) unsafe fn cast_unsized<U: 'a + ?Sized, F: FnOnce(*mut T) -> *mut U>(
114
            self,
115
            cast: F,
116
        ) -> Ptr<'a, U> {
117
            let ptr = cast(self.ptr.as_ptr());
118
            // SAFETY: Caller promises that `cast` is just an `as` cast. We call
119
            // `cast` on `self.ptr.as_ptr()`, which is non-null by construction.
120
            let ptr = unsafe { NonNull::new_unchecked(ptr) };
121
            // SAFETY:
122
            // - By invariant, `self.ptr` is derived from some valid Rust
123
            //   allocation, and since `ptr` is just `self.ptr as *mut U`, so is
124
            //   `ptr`.
125
            // - By invariant, `self.ptr` has the same provenance as `A`, and so
126
            //   the same is true of `ptr`.
127
            // - By invariant, `self.ptr` addresses a byte range which is
128
            //   entirely contained in `A`, and so the same is true of `ptr`.
129
            // - By invariant, `self.ptr` addresses a byte range whose length
130
            //   fits in an `isize`, and so the same is true of `ptr`.
131
            // - By invariant, `self.ptr` addresses a byte range which does not
132
            //   wrap around the address space, and so the same is true of
133
            //   `ptr`.
134
            // - By invariant, `self.ptr` is validly-aligned for `T`. Since
135
            //   `ptr` has the same address, and since the caller promises that
136
            //   the alignment of `U` is less than or equal to the alignment of
137
            //   `T`, `ptr` is validly-aligned for `U`.
138
            // - By invariant, `A` is guaranteed to live for at least `'a`.
139
            // - `U: 'a`
140
            Ptr { ptr, _lifetime: PhantomData }
141
        }
142
    }
143
144
    impl<'a> Ptr<'a, [u8]> {
145
        /// Attempts to cast `self` to a `U` using the given cast type.
146
        ///
147
        /// Returns `None` if the resulting `U` would be invalidly-aligned or if
148
        /// no `U` can fit in `self`. On success, returns a pointer to the
149
        /// largest-possible `U` which fits in `self`.
150
        ///
151
        /// # Safety
152
        ///
153
        /// The caller may assume that this implementation is correct, and may
154
        /// rely on that assumption for the soundness of their code. In
155
        /// particular, the caller may assume that, if `try_cast_into` returns
156
        /// `Some((ptr, split_at))`, then:
157
        /// - If this is a prefix cast, `ptr` refers to the byte range `[0,
158
        ///   split_at)` in `self`.
159
        /// - If this is a suffix cast, `ptr` refers to the byte range
160
        ///   `[split_at, self.len())` in `self`.
161
        ///
162
        /// # Panics
163
        ///
164
        /// Panics if `U` is a DST whose trailing slice element is zero-sized.
165
        pub(crate) fn try_cast_into<U: 'a + ?Sized + KnownLayout>(
166
            &self,
167
            cast_type: _CastType,
168
        ) -> Option<(Ptr<'a, U>, usize)> {
169
            // PANICS: By invariant, the byte range addressed by `self.ptr` does
170
            // not wrap around the address space. This implies that the sum of
171
            // the address (represented as a `usize`) and length do not overflow
172
            // `usize`, as required by `validate_cast_and_convert_metadata`.
173
            // Thus, this call to `validate_cast_and_convert_metadata` won't
174
            // panic.
175
            let (elems, split_at) = U::LAYOUT.validate_cast_and_convert_metadata(
176
                AsAddress::addr(self.ptr.as_ptr()),
177
                self.len(),
178
                cast_type,
179
            )?;
180
            let offset = match cast_type {
181
                _CastType::_Prefix => 0,
182
                _CastType::_Suffix => split_at,
183
            };
184
185
            let ptr = self.ptr.cast::<u8>().as_ptr();
186
            // SAFETY: `offset` is either `0` or `split_at`.
187
            // `validate_cast_and_convert_metadata` promises that `split_at` is
188
            // in the range `[0, self.len()]`. Thus, in both cases, `offset` is
189
            // in `[0, self.len()]`. Thus:
190
            // - The resulting pointer is in or one byte past the end of the
191
            //   same byte range as `self.ptr`. Since, by invariant, `self.ptr`
192
            //   addresses a byte range entirely contained within a single
193
            //   allocation, the pointer resulting from this operation is within
194
            //   or one byte past the end of that same allocation.
195
            // - By invariant, `self.len() <= isize::MAX`. Since `offset <=
196
            //   self.len()`, `offset <= isize::MAX`.
197
            // - By invariant, `self.ptr` addresses a byte range which does not
198
            //   wrap around the address space. This means that the base pointer
199
            //   plus the `self.len()` does not overflow `usize`. Since `offset
200
            //   <= self.len()`, this addition does not overflow `usize`.
201
            let base = unsafe { ptr.add(offset) };
202
            // SAFETY: Since `add` is not allowed to wrap around, the preceding line
203
            // produces a pointer whose address is greater than or equal to that of
204
            // `ptr`. Since `ptr` is a `NonNull`, `base` is also non-null.
205
            let base = unsafe { NonNull::new_unchecked(base) };
206
            let ptr = U::raw_from_ptr_len(base, elems);
207
            // SAFETY:
208
            // - By invariant, `self.ptr` is derived from some valid Rust
209
            //   allocation, `A`, and has the same provenance as `A`. All
210
            //   operations performed on `self.ptr` and values derived from it
211
            //   in this method preserve provenance, so:
212
            //   - `ptr` is derived from a valid Rust allocation, `A`.
213
            //   - `ptr` has the same provenance as `A`.
214
            // - `validate_cast_and_convert_metadata` promises that the object
215
            //   described by `elems` and `split_at` lives at a byte range which
216
            //   is a subset of the input byte range. Thus:
217
            //   - Since, by invariant, `self.ptr` addresses a byte range
218
            //     entirely contained in `A`, so does `ptr`.
219
            //   - Since, by invariant, `self.ptr` addresses a range whose
220
            //     length is not longer than `isize::MAX` bytes, so does `ptr`.
221
            //   - Since, by invariant, `self.ptr` addresses a range which does
222
            //     not wrap around the address space, so does `ptr`.
223
            // - `validate_cast_and_convert_metadata` promises that the object
224
            //   described by `split_at` is validly-aligned for `U`.
225
            // - By invariant on `self`, `A` is guaranteed to live for at least
226
            //   `'a`.
227
            // - `U: 'a` by trait bound.
228
            Some((Ptr { ptr, _lifetime: PhantomData }, split_at))
229
        }
230
231
        /// Attempts to cast `self` into a `U`, failing if all of the bytes of
232
        /// `self` cannot be treated as a `U`.
233
        ///
234
        /// In particular, this method fails if `self` is not validly-aligned
235
        /// for `U` or if `self`'s size is not a valid size for `U`.
236
        ///
237
        /// # Safety
238
        ///
239
        /// On success, the caller may assume that the returned pointer
240
        /// references the same byte range as `self`.
241
        #[allow(unused)]
242
        #[inline(always)]
243
        pub(crate) fn try_cast_into_no_leftover<U: 'a + ?Sized + KnownLayout>(
244
            &self,
245
        ) -> Option<Ptr<'a, U>> {
246
            // TODO(#67): Remove this allow. See NonNulSlicelExt for more
247
            // details.
248
            #[allow(unstable_name_collisions)]
249
            match self.try_cast_into(_CastType::_Prefix) {
250
                Some((slf, split_at)) if split_at == self.len() => Some(slf),
251
                Some(_) | None => None,
252
            }
253
        }
254
    }
255
256
    impl<'a, T> Ptr<'a, [T]> {
257
        /// The number of slice elements referenced by `self`.
258
        ///
259
        /// # Safety
260
        ///
261
        /// Unsafe code my rely on `len` satisfying the above contract.
262
        fn len(&self) -> usize {
263
            #[allow(clippy::as_conversions)]
264
            let slc = self.ptr.as_ptr() as *const [()];
265
            // SAFETY:
266
            // - `()` has alignment 1, so `slc` is trivially aligned.
267
            // - `slc` was derived from a non-null pointer.
268
            // - The size is 0 regardless of the length, so it is sound to
269
            //   materialize a reference regardless of location.
270
            // - By invariant, `self.ptr` has valid provenance.
271
            let slc = unsafe { &*slc };
272
            // This is correct because the preceding `as` cast preserves the
273
            // number of slice elements. Per
274
            // https://doc.rust-lang.org/nightly/reference/expressions/operator-expr.html#slice-dst-pointer-to-pointer-cast:
275
            //
276
            //   For slice types like `[T]` and `[U]`, the raw pointer types
277
            //   `*const [T]`, `*mut [T]`, `*const [U]`, and `*mut [U]` encode
278
            //   the number of elements in this slice. Casts between these raw
279
            //   pointer types preserve the number of elements. Note that, as a
280
            //   consequence, such casts do *not* necessarily preserve the size
281
            //   of the pointer's referent (e.g., casting `*const [u16]` to
282
            //   `*const [u8]` will result in a raw pointer which refers to an
283
            //   object of half the size of the original). The same holds for
284
            //   `str` and any compound type whose unsized tail is a slice type,
285
            //   such as struct `Foo(i32, [u8])` or `(u64, Foo)`.
286
            //
287
            // TODO(#429),
288
            // TODO(https://github.com/rust-lang/reference/pull/1417): Once this
289
            // text is available on the Stable docs, cite those instead of the
290
            // Nightly docs.
291
            slc.len()
292
        }
293
294
        pub(crate) fn iter(&self) -> impl Iterator<Item = Ptr<'a, T>> {
295
            // TODO(#429): Once `NonNull::cast` documents that it preserves
296
            // provenance, cite those docs.
297
            let base = self.ptr.cast::<T>().as_ptr();
298
            (0..self.len()).map(move |i| {
299
                // TODO(https://github.com/rust-lang/rust/issues/74265): Use
300
                // `NonNull::get_unchecked_mut`.
301
302
                // SAFETY: If the following conditions are not satisfied
303
                // `pointer::cast` may induce Undefined Behavior [1]:
304
                // > 1. Both the starting and resulting pointer must be either
305
                // >    in bounds or one byte past the end of the same allocated
306
                // >    object.
307
                // > 2. The computed offset, in bytes, cannot overflow an
308
                // >    `isize`.
309
                // > 3. The offset being in bounds cannot rely on “wrapping
310
                // >    around” the address space. That is, the
311
                // >    infinite-precision sum must fit in a `usize`.
312
                //
313
                // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add
314
                //
315
                // We satisfy all three of these conditions here:
316
                // 1. `base` (by invariant on `self`) points to an allocated
317
                //    object. By contract, `self.len()` accurately reflects the
318
                //    number of elements in the slice. `i` is in bounds of
319
                //   `c.len()` by construction, and so the result of this
320
                //   addition cannot overflow past the end of the allocation
321
                //   referred to by `c`.
322
                // 2. By invariant on `Ptr`, `self` addresses a byte range whose
323
                //    length fits in an `isize`. Since `elem` is contained in
324
                //    `self`, the computed offset of `elem` must fit within
325
                //    `isize.`
326
                // 3. By invariant on `Ptr`, `self` addresses a byte range which
327
                //    does not wrap around the address space. Since `elem` is
328
                //    contained in `self`, the computed offset of `elem` must
329
                //    wrap around the address space.
330
                //
331
                // TODO(#429): Once `pointer::add` documents that it preserves
332
                // provenance, cite those docs.
333
                let elem = unsafe { base.add(i) };
334
335
                // SAFETY:
336
                //  - `elem` must not be null. `base` is constructed from a
337
                //    `NonNull` pointer, and the addition that produces `elem`
338
                //    must not overflow or wrap around, so `elem >= base > 0`.
339
                //
340
                // TODO(#429): Once `NonNull::new_unchecked` documents that it
341
                // preserves provenance, cite those docs.
342
                let elem = unsafe { NonNull::new_unchecked(elem) };
343
344
                // SAFETY: The safety invariants of `Ptr` (see definition) are
345
                // satisfied:
346
                // 1. `elem` is derived from a valid Rust allocation, because
347
                //    `self` is derived from a valid Rust allocation, by
348
                //    invariant on `Ptr`
349
                // 2. `elem` has the same provenance as `self`, because it
350
                //    derived from `self` using a series of
351
                //    provenance-preserving operations
352
                // 3. `elem` is entirely contained in the allocation of `self`
353
                //    (see above)
354
                // 4. `elem` addresses a byte range whose length fits in an
355
                //    `isize` (see above)
356
                // 5. `elem` addresses a byte range which does not wrap around
357
                //    the address space (see above)
358
                // 6. `elem` is validly-aligned for `T`. `self`, which
359
                //    represents a `[T]` is validly aligned for `T`, and `elem`
360
                //    is an element within that `[T]`
361
                // 7. The allocation of `elem` is guaranteed to live for at
362
                //    least `'a`, because `elem` is entirely contained in
363
                //    `self`, which lives for at least `'a` by invariant on
364
                //    `Ptr`.
365
                // 8. `T: 'a`, because `elem` is an element within `[T]`, and
366
                //    `[T]: 'a` by invariant on `Ptr`
367
                Ptr { ptr: elem, _lifetime: PhantomData }
368
            })
369
        }
370
    }
371
372
    impl<'a, T: 'a + ?Sized> From<&'a T> for Ptr<'a, T> {
373
        #[inline(always)]
374
        fn from(t: &'a T) -> Ptr<'a, T> {
375
            // SAFETY: `t` points to a valid Rust allocation, `A`, by
376
            // construction. Thus:
377
            // - `ptr` is derived from `A`
378
            // - Since we use `NonNull::from`, which preserves provenance, `ptr`
379
            //   has the same provenance as `A`
380
            // - Since `NonNull::from` creates a pointer which addresses the
381
            //   same bytes as `t`, `ptr` addresses a byte range entirely
382
            //   contained in (in this case, identical to) `A`
383
            // - Since `t: &T`, it addresses no more than `isize::MAX` bytes [1]
384
            // - Since `t: &T`, it addresses a byte range which does not wrap
385
            //   around the address space [2]
386
            // - Since it is constructed from a valid `&T`, `ptr` is
387
            //   validly-aligned for `T`
388
            // - Since `t: &'a T`, the allocation `A` is guaranteed to live for
389
            //   at least `'a`
390
            // - `T: 'a` by trait bound
391
            //
392
            // TODO(#429),
393
            // TODO(https://github.com/rust-lang/rust/issues/116181): Once it's
394
            // documented, reference the guarantee that `NonNull::from`
395
            // preserves provenance.
396
            //
397
            // TODO(#429),
398
            // TODO(https://github.com/rust-lang/unsafe-code-guidelines/issues/465):
399
            // - [1] Where does the reference document that allocations fit in
400
            //   `isize`?
401
            // - [2] Where does the reference document that allocations don't
402
            //   wrap around the address space?
403
            Ptr { ptr: NonNull::from(t), _lifetime: PhantomData }
404
        }
405
    }
406
407
    impl<'a, T: 'a + ?Sized> Debug for Ptr<'a, T> {
408
        #[inline]
409
        fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
410
            self.ptr.fmt(f)
411
        }
412
    }
413
414
    #[cfg(test)]
415
    mod tests {
416
        use core::mem::{self, MaybeUninit};
417
418
        use super::*;
419
        use crate::{util::testutil::AU64, FromBytes};
420
421
        #[test]
422
        fn test_ptrtry_cast_into_soundness() {
423
            // This test is designed so that if `Ptr::try_cast_into_xxx` are
424
            // buggy, it will manifest as unsoundness that Miri can detect.
425
426
            // - If `size_of::<T>() == 0`, `N == 4`
427
            // - Else, `N == 4 * size_of::<T>()`
428
            fn test<const N: usize, T: ?Sized + KnownLayout + FromBytes>() {
429
                let mut bytes = [MaybeUninit::<u8>::uninit(); N];
430
                let initialized = [MaybeUninit::new(0u8); N];
431
                for start in 0..=bytes.len() {
432
                    for end in start..=bytes.len() {
433
                        // Set all bytes to uninitialized other than those in
434
                        // the range we're going to pass to `try_cast_from`.
435
                        // This allows Miri to detect out-of-bounds reads
436
                        // because they read uninitialized memory. Without this,
437
                        // some out-of-bounds reads would still be in-bounds of
438
                        // `bytes`, and so might spuriously be accepted.
439
                        bytes = [MaybeUninit::<u8>::uninit(); N];
440
                        let bytes = &mut bytes[start..end];
441
                        // Initialize only the byte range we're going to pass to
442
                        // `try_cast_from`.
443
                        bytes.copy_from_slice(&initialized[start..end]);
444
445
                        let bytes = {
446
                            let bytes: *const [MaybeUninit<u8>] = bytes;
447
                            #[allow(clippy::as_conversions)]
448
                            let bytes = bytes as *const [u8];
449
                            // SAFETY: We just initialized these bytes to valid
450
                            // `u8`s.
451
                            unsafe { &*bytes }
452
                        };
453
454
                        /// # Safety
455
                        ///
456
                        /// - `slf` must reference a byte range which is
457
                        ///   entirely initialized.
458
                        /// - `slf` must reference a byte range which is only
459
                        ///   referenced by shared references which do not
460
                        ///   contain `UnsafeCell`s during its lifetime.
461
                        unsafe fn validate_and_get_len<T: ?Sized + KnownLayout + FromBytes>(
462
                            slf: Ptr<'_, T>,
463
                        ) -> usize {
464
                            // SAFETY:
465
                            // - Since all bytes in `slf` are initialized and
466
                            //   `T: FromBytes`, `slf` contains a valid `T`.
467
                            // - The caller promises that the referenced memory
468
                            //   is not also referenced by any mutable
469
                            //   references.
470
                            // - The caller promises that the referenced memory
471
                            //   is not also referenced as a type which contains
472
                            //   `UnsafeCell`s.
473
                            let t = unsafe { slf.as_ref() };
474
475
                            let bytes = {
476
                                let len = mem::size_of_val(t);
477
                                let t: *const T = t;
478
                                // SAFETY:
479
                                // - We know `t`'s bytes are all initialized
480
                                //   because we just read it from `slf`, which
481
                                //   points to an initialized range of bytes. If
482
                                //   there's a bug and this doesn't hold, then
483
                                //   that's exactly what we're hoping Miri will
484
                                //   catch!
485
                                // - Since `T: FromBytes`, `T` doesn't contain
486
                                //   any `UnsafeCell`s, so it's okay for `t: T`
487
                                //   and a `&[u8]` to the same memory to be
488
                                //   alive concurrently.
489
                                unsafe { core::slice::from_raw_parts(t.cast::<u8>(), len) }
490
                            };
491
492
                            // This assertion ensures that `t`'s bytes are read
493
                            // and compared to another value, which in turn
494
                            // ensures that Miri gets a chance to notice if any
495
                            // of `t`'s bytes are uninitialized, which they
496
                            // shouldn't be (see the comment above).
497
                            assert_eq!(bytes, vec![0u8; bytes.len()]);
498
499
                            mem::size_of_val(t)
500
                        }
501
502
                        for cast_type in [_CastType::_Prefix, _CastType::_Suffix] {
503
                            if let Some((slf, split_at)) =
504
                                Ptr::from(bytes).try_cast_into::<T>(cast_type)
505
                            {
506
                                // SAFETY: All bytes in `bytes` have been
507
                                // initialized.
508
                                let len = unsafe { validate_and_get_len(slf) };
509
                                match cast_type {
510
                                    _CastType::_Prefix => assert_eq!(split_at, len),
511
                                    _CastType::_Suffix => assert_eq!(split_at, bytes.len() - len),
512
                                }
513
                            }
514
                        }
515
516
                        if let Some(slf) = Ptr::from(bytes).try_cast_into_no_leftover::<T>() {
517
                            // SAFETY: All bytes in `bytes` have been
518
                            // initialized.
519
                            let len = unsafe { validate_and_get_len(slf) };
520
                            assert_eq!(len, bytes.len());
521
                        }
522
                    }
523
                }
524
            }
525
526
            macro_rules! test {
527
            ($($ty:ty),*) => {
528
                $({
529
                    const S: usize = core::mem::size_of::<$ty>();
530
                    const N: usize = if S == 0 { 4 } else { S * 4 };
531
                    test::<N, $ty>();
532
                    // We don't support casting into DSTs whose trailing slice
533
                    // element is a ZST.
534
                    if S > 0 {
535
                        test::<N, [$ty]>();
536
                    }
537
                    // TODO: Test with a slice DST once we have any that
538
                    // implement `KnownLayout + FromBytes`.
539
                })*
540
            };
541
        }
542
543
            test!(());
544
            test!(u8, u16, u32, u64, u128, usize, AU64);
545
            test!(i8, i16, i32, i64, i128, isize);
546
            test!(f32, f64);
547
        }
548
    }
549
}
550
551
pub(crate) trait AsAddress {
552
    fn addr(self) -> usize;
553
}
554
555
impl<'a, T: ?Sized> AsAddress for &'a T {
556
    #[inline(always)]
557
2.33M
    fn addr(self) -> usize {
558
2.33M
        let ptr: *const T = self;
559
2.33M
        AsAddress::addr(ptr)
560
2.33M
    }
Unexecuted instantiation: <&[u8] as zerocopy::util::AsAddress>::addr
Unexecuted instantiation: <&[u8] as zerocopy::util::AsAddress>::addr
<&[u8] as zerocopy::util::AsAddress>::addr
Line
Count
Source
557
1.32k
    fn addr(self) -> usize {
558
1.32k
        let ptr: *const T = self;
559
1.32k
        AsAddress::addr(ptr)
560
1.32k
    }
Unexecuted instantiation: <&[u8] as zerocopy::util::AsAddress>::addr
Unexecuted instantiation: <&[u8] as zerocopy::util::AsAddress>::addr
<&[u8] as zerocopy::util::AsAddress>::addr
Line
Count
Source
557
2.33M
    fn addr(self) -> usize {
558
2.33M
        let ptr: *const T = self;
559
2.33M
        AsAddress::addr(ptr)
560
2.33M
    }
561
}
562
563
impl<'a, T: ?Sized> AsAddress for &'a mut T {
564
    #[inline(always)]
565
    fn addr(self) -> usize {
566
        let ptr: *const T = self;
567
        AsAddress::addr(ptr)
568
    }
569
}
570
571
impl<T: ?Sized> AsAddress for *const T {
572
    #[inline(always)]
573
2.33M
    fn addr(self) -> usize {
574
2.33M
        // TODO(#181), TODO(https://github.com/rust-lang/rust/issues/95228): Use
575
2.33M
        // `.addr()` instead of `as usize` once it's stable, and get rid of this
576
2.33M
        // `allow`. Currently, `as usize` is the only way to accomplish this.
577
2.33M
        #[allow(clippy::as_conversions)]
578
2.33M
        #[cfg_attr(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS, allow(lossy_provenance_casts))]
579
2.33M
        return self.cast::<()>() as usize;
580
2.33M
    }
Unexecuted instantiation: <*const [u8] as zerocopy::util::AsAddress>::addr
Unexecuted instantiation: <*const [u8] as zerocopy::util::AsAddress>::addr
<*const [u8] as zerocopy::util::AsAddress>::addr
Line
Count
Source
573
1.32k
    fn addr(self) -> usize {
574
1.32k
        // TODO(#181), TODO(https://github.com/rust-lang/rust/issues/95228): Use
575
1.32k
        // `.addr()` instead of `as usize` once it's stable, and get rid of this
576
1.32k
        // `allow`. Currently, `as usize` is the only way to accomplish this.
577
1.32k
        #[allow(clippy::as_conversions)]
578
1.32k
        #[cfg_attr(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS, allow(lossy_provenance_casts))]
579
1.32k
        return self.cast::<()>() as usize;
580
1.32k
    }
Unexecuted instantiation: <*const [u8] as zerocopy::util::AsAddress>::addr
Unexecuted instantiation: <*const [u8] as zerocopy::util::AsAddress>::addr
<*const [u8] as zerocopy::util::AsAddress>::addr
Line
Count
Source
573
2.33M
    fn addr(self) -> usize {
574
2.33M
        // TODO(#181), TODO(https://github.com/rust-lang/rust/issues/95228): Use
575
2.33M
        // `.addr()` instead of `as usize` once it's stable, and get rid of this
576
2.33M
        // `allow`. Currently, `as usize` is the only way to accomplish this.
577
2.33M
        #[allow(clippy::as_conversions)]
578
2.33M
        #[cfg_attr(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS, allow(lossy_provenance_casts))]
579
2.33M
        return self.cast::<()>() as usize;
580
2.33M
    }
581
}
582
583
impl<T: ?Sized> AsAddress for *mut T {
584
    #[inline(always)]
585
    fn addr(self) -> usize {
586
        let ptr: *const T = self;
587
        AsAddress::addr(ptr)
588
    }
589
}
590
591
/// Is `t` aligned to `mem::align_of::<U>()`?
592
#[inline(always)]
593
2.33M
pub(crate) fn aligned_to<T: AsAddress, U>(t: T) -> bool {
594
2.33M
    // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
595
2.33M
    // turn guarantees that this mod operation will not panic.
596
2.33M
    #[allow(clippy::arithmetic_side_effects)]
597
2.33M
    let remainder = t.addr() % mem::align_of::<U>();
598
2.33M
    remainder == 0
599
2.33M
}
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<base::sys::linux::acpi_event::AcpiGenlEvent>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<base::sys::linux::netlink::GenlMsgHdr>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<base::sys::linux::netlink::NlAttr>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<base::sys::linux::netlink::NlMsgHdr>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], base::sys::linux::netlink::GenlMsgHdr>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], base::sys::linux::netlink::NlAttr>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], base::sys::linux::netlink::NlMsgHdr>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<vfio_sys::vfio::vfio_iova_range>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<vfio_sys::vfio::vfio_info_cap_header>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<vfio_sys::vfio::vfio_iommu_type1_info_cap_iova_range_header>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<virtio_sys::virtio_scsi::virtio_scsi_config>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<vmm_vhost::message::VhostUserU64>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<vmm_vhost::message::VhostUserInflight>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<vmm_vhost::message::VhostUserVringAddr>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<vmm_vhost::message::VhostUserVringState>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<vmm_vhost::message::VhostUserSingleMemoryRegion>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<vmm_vhost::message::DeviceStateTransferParameters>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::fs::read_dir::LinuxDirent64>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::ModeSense6>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::ReportLuns>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::ModeSelect6>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::WriteSame10>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::WriteSame16>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::TestUnitReady>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::ReadCapacity10>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::ReadCapacity16>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::SynchronizeCache10>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::ReportSupportedTMFs>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::Read6>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::Unmap>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::Read10>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::Inquiry>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<devices::virtio::scsi::commands::Write10>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<u8>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<u32>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<u16>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], vmm_vhost::message::VhostUserConfig>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], vmm_vhost::message::VhostUserMemory>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], vmm_vhost::message::VhostUserMemoryRegion>
zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<fuse::sys::SecctxHeader>>
Line
Count
Source
593
556
pub(crate) fn aligned_to<T: AsAddress, U>(t: T) -> bool {
594
556
    // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
595
556
    // turn guarantees that this mod operation will not panic.
596
556
    #[allow(clippy::arithmetic_side_effects)]
597
556
    let remainder = t.addr() % mem::align_of::<U>();
598
556
    remainder == 0
599
556
}
zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<fuse::sys::Secctx>>
Line
Count
Source
593
771
pub(crate) fn aligned_to<T: AsAddress, U>(t: T) -> bool {
594
771
    // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
595
771
    // turn guarantees that this mod operation will not panic.
596
771
    #[allow(clippy::arithmetic_side_effects)]
597
771
    let remainder = t.addr() % mem::align_of::<U>();
598
771
    remainder == 0
599
771
}
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<vmm_vhost::message::VhostSharedMemoryRegion>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::cross_domain::CrossDomainInitLegacy>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::cross_domain::cross_domain_protocol::CrossDomainInit>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::cross_domain::cross_domain_protocol::CrossDomainHeader>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::cross_domain::cross_domain_protocol::CrossDomainReadWrite>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::cross_domain::cross_domain_protocol::CrossDomainSendReceive>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::cross_domain::cross_domain_protocol::CrossDomainGetImageRequirements>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::ipc::kumquat_gpu_protocol::kumquat_gpu_protocol_ctrl_hdr>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::ipc::kumquat_gpu_protocol::kumquat_gpu_protocol_cmd_submit>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::ipc::kumquat_gpu_protocol::kumquat_gpu_protocol_ctx_create>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::ipc::kumquat_gpu_protocol::kumquat_gpu_protocol_get_capset>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::ipc::kumquat_gpu_protocol::kumquat_gpu_protocol_ctx_resource>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::ipc::kumquat_gpu_protocol::kumquat_gpu_protocol_resp_capset_info>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::ipc::kumquat_gpu_protocol::kumquat_gpu_protocol_transfer_host_3d>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::ipc::kumquat_gpu_protocol::kumquat_gpu_protocol_resource_create_3d>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::ipc::kumquat_gpu_protocol::kumquat_gpu_protocol_resp_cmd_submit_3d>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::ipc::kumquat_gpu_protocol::kumquat_gpu_protocol_resource_create_blob>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<rutabaga_gfx::ipc::kumquat_gpu_protocol::kumquat_gpu_protocol_resp_resource_create>>
Unexecuted instantiation: zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<u64>>
zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<usb_util::types::ConfigDescriptor>>
Line
Count
Source
593
18.4k
pub(crate) fn aligned_to<T: AsAddress, U>(t: T) -> bool {
594
18.4k
    // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
595
18.4k
    // turn guarantees that this mod operation will not panic.
596
18.4k
    #[allow(clippy::arithmetic_side_effects)]
597
18.4k
    let remainder = t.addr() % mem::align_of::<U>();
598
18.4k
    remainder == 0
599
18.4k
}
zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<usb_util::types::DescriptorHeader>>
Line
Count
Source
593
1.60M
pub(crate) fn aligned_to<T: AsAddress, U>(t: T) -> bool {
594
1.60M
    // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
595
1.60M
    // turn guarantees that this mod operation will not panic.
596
1.60M
    #[allow(clippy::arithmetic_side_effects)]
597
1.60M
    let remainder = t.addr() % mem::align_of::<U>();
598
1.60M
    remainder == 0
599
1.60M
}
zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<usb_util::types::DeviceDescriptor>>
Line
Count
Source
593
1.11k
pub(crate) fn aligned_to<T: AsAddress, U>(t: T) -> bool {
594
1.11k
    // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
595
1.11k
    // turn guarantees that this mod operation will not panic.
596
1.11k
    #[allow(clippy::arithmetic_side_effects)]
597
1.11k
    let remainder = t.addr() % mem::align_of::<U>();
598
1.11k
    remainder == 0
599
1.11k
}
zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<usb_util::types::EndpointDescriptor>>
Line
Count
Source
593
442k
pub(crate) fn aligned_to<T: AsAddress, U>(t: T) -> bool {
594
442k
    // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
595
442k
    // turn guarantees that this mod operation will not panic.
596
442k
    #[allow(clippy::arithmetic_side_effects)]
597
442k
    let remainder = t.addr() % mem::align_of::<U>();
598
442k
    remainder == 0
599
442k
}
zerocopy::util::aligned_to::<&[u8], zerocopy::wrappers::Unalign<usb_util::types::InterfaceDescriptor>>
Line
Count
Source
593
269k
pub(crate) fn aligned_to<T: AsAddress, U>(t: T) -> bool {
594
269k
    // `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
595
269k
    // turn guarantees that this mod operation will not panic.
596
269k
    #[allow(clippy::arithmetic_side_effects)]
597
269k
    let remainder = t.addr() % mem::align_of::<U>();
598
269k
    remainder == 0
599
269k
}
600
601
/// Round `n` down to the largest value `m` such that `m <= n` and `m % align ==
602
/// 0`.
603
///
604
/// # Panics
605
///
606
/// May panic if `align` is not a power of two. Even if it doesn't panic in this
607
/// case, it will produce nonsense results.
608
#[inline(always)]
609
pub(crate) const fn round_down_to_next_multiple_of_alignment(
610
    n: usize,
611
    align: NonZeroUsize,
612
) -> usize {
613
    let align = align.get();
614
    debug_assert!(align.is_power_of_two());
615
616
    // Subtraction can't underflow because `align.get() >= 1`.
617
    #[allow(clippy::arithmetic_side_effects)]
618
    let mask = !(align - 1);
619
    n & mask
620
}
621
622
pub(crate) const fn max(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
623
    if a.get() < b.get() {
624
        b
625
    } else {
626
        a
627
    }
628
}
629
630
pub(crate) const fn min(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
631
    if a.get() > b.get() {
632
        b
633
    } else {
634
        a
635
    }
636
}
637
638
/// Since we support multiple versions of Rust, there are often features which
639
/// have been stabilized in the most recent stable release which do not yet
640
/// exist (stably) on our MSRV. This module provides polyfills for those
641
/// features so that we can write more "modern" code, and just remove the
642
/// polyfill once our MSRV supports the corresponding feature. Without this,
643
/// we'd have to write worse/more verbose code and leave TODO comments sprinkled
644
/// throughout the codebase to update to the new pattern once it's stabilized.
645
///
646
/// Each trait is imported as `_` at the crate root; each polyfill should "just
647
/// work" at usage sites.
648
pub(crate) mod polyfills {
649
    use core::ptr::{self, NonNull};
650
651
    // A polyfill for `NonNull::slice_from_raw_parts` that we can use before our
652
    // MSRV is 1.70, when that function was stabilized.
653
    //
654
    // TODO(#67): Once our MSRV is 1.70, remove this.
655
    pub(crate) trait NonNullExt<T> {
656
        fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]>;
657
    }
658
659
    impl<T> NonNullExt<T> for NonNull<T> {
660
        #[inline(always)]
661
        fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]> {
662
            let ptr = ptr::slice_from_raw_parts_mut(data.as_ptr(), len);
663
            // SAFETY: `ptr` is converted from `data`, which is non-null.
664
            unsafe { NonNull::new_unchecked(ptr) }
665
        }
666
    }
667
}
668
669
#[cfg(test)]
670
pub(crate) mod testutil {
671
    use core::fmt::{self, Display, Formatter};
672
673
    use crate::*;
674
675
    /// A `T` which is aligned to at least `align_of::<A>()`.
676
    #[derive(Default)]
677
    pub(crate) struct Align<T, A> {
678
        pub(crate) t: T,
679
        _a: [A; 0],
680
    }
681
682
    impl<T: Default, A> Align<T, A> {
683
        pub(crate) fn set_default(&mut self) {
684
            self.t = T::default();
685
        }
686
    }
687
688
    impl<T, A> Align<T, A> {
689
        pub(crate) const fn new(t: T) -> Align<T, A> {
690
            Align { t, _a: [] }
691
        }
692
    }
693
694
    // A `u64` with alignment 8.
695
    //
696
    // Though `u64` has alignment 8 on some platforms, it's not guaranteed.
697
    // By contrast, `AU64` is guaranteed to have alignment 8.
698
    #[derive(
699
        KnownLayout,
700
        FromZeroes,
701
        FromBytes,
702
        AsBytes,
703
        Eq,
704
        PartialEq,
705
        Ord,
706
        PartialOrd,
707
        Default,
708
        Debug,
709
        Copy,
710
        Clone,
711
    )]
712
    #[repr(C, align(8))]
713
    pub(crate) struct AU64(pub(crate) u64);
714
715
    impl AU64 {
716
        // Converts this `AU64` to bytes using this platform's endianness.
717
        pub(crate) fn to_bytes(self) -> [u8; 8] {
718
            crate::transmute!(self)
719
        }
720
    }
721
722
    impl Display for AU64 {
723
        fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
724
            Display::fmt(&self.0, f)
725
        }
726
    }
727
728
    #[derive(
729
        FromZeroes, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone,
730
    )]
731
    #[repr(C)]
732
    pub(crate) struct Nested<T, U: ?Sized> {
733
        _t: T,
734
        _u: U,
735
    }
736
}
737
738
#[cfg(test)]
739
mod tests {
740
    use super::*;
741
742
    #[test]
743
    fn test_round_down_to_next_multiple_of_alignment() {
744
        fn alt_impl(n: usize, align: NonZeroUsize) -> usize {
745
            let mul = n / align.get();
746
            mul * align.get()
747
        }
748
749
        for align in [1, 2, 4, 8, 16] {
750
            for n in 0..256 {
751
                let align = NonZeroUsize::new(align).unwrap();
752
                let want = alt_impl(n, align);
753
                let got = round_down_to_next_multiple_of_alignment(n, align);
754
                assert_eq!(got, want, "round_down_to_next_multiple_of_alignment({n}, {align})");
755
            }
756
        }
757
    }
758
}
759
760
#[cfg(kani)]
761
mod proofs {
762
    use super::*;
763
764
    #[kani::proof]
765
    fn prove_round_down_to_next_multiple_of_alignment() {
766
        fn model_impl(n: usize, align: NonZeroUsize) -> usize {
767
            assert!(align.get().is_power_of_two());
768
            let mul = n / align.get();
769
            mul * align.get()
770
        }
771
772
        let align: NonZeroUsize = kani::any();
773
        kani::assume(align.get().is_power_of_two());
774
        let n: usize = kani::any();
775
776
        let expected = model_impl(n, align);
777
        let actual = round_down_to_next_multiple_of_alignment(n, align);
778
        assert_eq!(expected, actual, "round_down_to_next_multiple_of_alignment({n}, {align})");
779
    }
780
781
    // Restricted to nightly since we use the unstable `usize::next_multiple_of`
782
    // in our model implementation.
783
    #[cfg(__INTERNAL_USE_ONLY_NIGHLTY_FEATURES_IN_TESTS)]
784
    #[kani::proof]
785
    fn prove_padding_needed_for() {
786
        fn model_impl(len: usize, align: NonZeroUsize) -> usize {
787
            let padded = len.next_multiple_of(align.get());
788
            let padding = padded - len;
789
            padding
790
        }
791
792
        let align: NonZeroUsize = kani::any();
793
        kani::assume(align.get().is_power_of_two());
794
        let len: usize = kani::any();
795
        // Constrain `len` to valid Rust lengths, since our model implementation
796
        // isn't robust to overflow.
797
        kani::assume(len <= isize::MAX as usize);
798
        kani::assume(align.get() < 1 << 29);
799
800
        let expected = model_impl(len, align);
801
        let actual = core_layout::padding_needed_for(len, align);
802
        assert_eq!(expected, actual, "padding_needed_for({len}, {align})");
803
804
        let padded_len = actual + len;
805
        assert_eq!(padded_len % align, 0);
806
        assert!(padded_len / align >= len / align);
807
    }
808
}