Coverage Report

Created: 2026-10-28 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zerocopy-0.8.63/src/pointer/inner.rs
Line
Count
Source
1
// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0 OR MIT
2
//
3
// Copyright 2024 The Fuchsia Authors
4
//
5
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
6
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
7
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
8
// This file may not be copied, modified, or distributed except according to
9
// those terms.
10
11
use core::{marker::PhantomData, ops::Range, ptr::NonNull};
12
13
pub use _def::PtrInner;
14
15
#[allow(unused_imports)]
16
use crate::util::polyfills::NumExt as _;
17
use crate::{
18
    layout::{CastType, MetadataCastError},
19
    pointer::cast,
20
    util::AsAddress,
21
    AlignmentError, CastError, KnownLayout, MetadataOf, SizeError, SplitAt,
22
};
23
24
mod _def {
25
    use super::*;
26
    /// The inner pointer stored inside a [`Ptr`][crate::Ptr].
27
    ///
28
    /// `PtrInner<'a, T>` is [covariant] in `'a` and invariant in `T`.
29
    ///
30
    /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
31
    #[allow(missing_debug_implementations)]
32
    pub struct PtrInner<'a, T>
33
    where
34
        T: ?Sized,
35
    {
36
        /// # Invariants
37
        ///
38
        /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid
39
        ///    provenance for its referent, which is entirely contained in some
40
        ///    Rust allocation, `A`.
41
        /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live
42
        ///    for at least `'a`.
43
        ///
44
        /// # Postconditions
45
        ///
46
        /// By virtue of these invariants, code may assume the following, which
47
        /// are logical implications of the invariants:
48
        /// - `ptr`'s referent is not larger than `isize::MAX` bytes \[1\]
49
        /// - `ptr`'s referent does not wrap around the address space \[1\]
50
        ///
51
        /// \[1\] Per <https://doc.rust-lang.org/1.85.0/std/ptr/index.html#allocated-object>:
52
        ///
53
        ///   For any allocated object with `base` address, `size`, and a set of
54
        ///   `addresses`, the following are guaranteed:
55
        ///   ...
56
        ///   - `size <= isize::MAX`
57
        ///
58
        ///   As a consequence of these guarantees, given any address `a` within
59
        ///   the set of addresses of an allocated object:
60
        ///   ...
61
        ///   - It is guaranteed that, given `o = a - base` (i.e., the offset of
62
        ///     `a` within the allocated object), `base + o` will not wrap
63
        ///     around the address space (in other words, will not overflow
64
        ///     `usize`)
65
        ptr: NonNull<T>,
66
        // SAFETY: `&'a UnsafeCell<T>` is covariant in `'a` and invariant in `T`
67
        // [1]. We use this construction rather than the equivalent `&mut T`,
68
        // because our MSRV of 1.65 prohibits `&mut` types in const contexts.
69
        //
70
        // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance
71
        _marker: PhantomData<&'a core::cell::UnsafeCell<T>>,
72
    }
73
74
    impl<'a, T: 'a + ?Sized> Copy for PtrInner<'a, T> {}
75
    impl<'a, T: 'a + ?Sized> Clone for PtrInner<'a, T> {
76
        #[inline(always)]
77
        fn clone(&self) -> PtrInner<'a, T> {
78
            // SAFETY: None of the invariants on `ptr` are affected by having
79
            // multiple copies of a `PtrInner`.
80
            *self
81
        }
82
    }
83
84
    impl<'a, T: 'a + ?Sized> PtrInner<'a, T> {
85
        /// Constructs a `Ptr` from a [`NonNull`].
86
        ///
87
        /// # Safety
88
        ///
89
        /// The caller promises that:
90
        ///
91
        /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid
92
        ///    provenance for its referent, which is entirely contained in some
93
        ///    Rust allocation, `A`.
94
        /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live
95
        ///    for at least `'a`.
96
        #[inline(always)]
97
        #[must_use]
98
0
        pub const unsafe fn new(ptr: NonNull<T>) -> PtrInner<'a, T> {
99
            // SAFETY: The caller has promised to satisfy all safety invariants
100
            // of `PtrInner`.
101
0
            Self { ptr, _marker: PhantomData }
102
0
        }
Unexecuted instantiation: <zerocopy::pointer::inner::_def::PtrInner<[half::binary16::f16]>>::new
Unexecuted instantiation: <zerocopy::pointer::inner::_def::PtrInner<[u16]>>::new
103
104
        /// Converts this `PtrInner<T>` to a [`NonNull<T>`].
105
        ///
106
        /// Note that this method does not consume `self`. The caller should
107
        /// watch out for `unsafe` code which uses the returned `NonNull` in a
108
        /// way that violates the safety invariants of `self`.
109
        #[inline(always)]
110
        #[must_use]
111
0
        pub const fn as_non_null(&self) -> NonNull<T> {
112
0
            self.ptr
113
0
        }
Unexecuted instantiation: <zerocopy::pointer::inner::_def::PtrInner<[half::binary16::f16]>>::as_non_null
Unexecuted instantiation: <zerocopy::pointer::inner::_def::PtrInner<[u16]>>::as_non_null
114
115
        /// Converts this `PtrInner<T>` to a [`*mut T`].
116
        ///
117
        /// Note that this method does not consume `self`. The caller should
118
        /// watch out for `unsafe` code which uses the returned `*mut T` in a
119
        /// way that violates the safety invariants of `self`.
120
        #[inline(always)]
121
        #[must_use]
122
0
        pub const fn as_ptr(&self) -> *mut T {
123
0
            self.ptr.as_ptr()
124
0
        }
Unexecuted instantiation: <zerocopy::pointer::inner::_def::PtrInner<[half::binary16::f16]>>::as_ptr
Unexecuted instantiation: <zerocopy::pointer::inner::_def::PtrInner<[u16]>>::as_ptr
125
    }
126
}
127
128
impl<'a, T: ?Sized> PtrInner<'a, T> {
129
    /// Constructs a `PtrInner` from a reference.
130
    #[inline]
131
    pub fn from_ref(ptr: &'a T) -> Self {
132
        let ptr = NonNull::from(ptr);
133
        // SAFETY:
134
        // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on
135
        //    `&'a T` [1], has valid provenance for its referent, which is
136
        //    entirely contained in some Rust allocation, `A`.
137
        // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on
138
        //    `&'a T`, is guaranteed to live for at least `'a`.
139
        //
140
        // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety:
141
        //
142
        //   For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`,
143
        //   when such values cross an API boundary, the following invariants
144
        //   must generally be upheld:
145
        //   ...
146
        //   - if `size_of_val(t) > 0`, then `t` is dereferenceable for
147
        //     `size_of_val(t)` many bytes
148
        //
149
        //   If `t` points at address `a`, being “dereferenceable” for N bytes
150
        //   means that the memory range `[a, a + N)` is all contained within a
151
        //   single allocated object.
152
        unsafe { Self::new(ptr) }
153
    }
154
155
    /// Constructs a `PtrInner` from a mutable reference.
156
    #[inline]
157
0
    pub fn from_mut(ptr: &'a mut T) -> Self {
158
0
        let ptr = NonNull::from(ptr);
159
        // SAFETY:
160
        // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on
161
        //    `&'a mut T` [1], has valid provenance for its referent, which is
162
        //    entirely contained in some Rust allocation, `A`.
163
        // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on
164
        //    `&'a mut T`, is guaranteed to live for at least `'a`.
165
        //
166
        // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety:
167
        //
168
        //   For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`,
169
        //   when such values cross an API boundary, the following invariants
170
        //   must generally be upheld:
171
        //   ...
172
        //   - if `size_of_val(t) > 0`, then `t` is dereferenceable for
173
        //     `size_of_val(t)` many bytes
174
        //
175
        //   If `t` points at address `a`, being “dereferenceable” for N bytes
176
        //   means that the memory range `[a, a + N)` is all contained within a
177
        //   single allocated object.
178
0
        unsafe { Self::new(ptr) }
179
0
    }
180
181
    /// # Safety
182
    ///
183
    /// The caller may assume that the resulting `PtrInner` addresses the subset
184
    /// of the bytes of `self`'s referent addressed by `C::project(self)`.
185
    #[must_use]
186
    #[inline(always)]
187
0
    pub fn project<U: ?Sized, C: cast::Project<T, U>>(self) -> PtrInner<'a, U> {
188
0
        let projected_raw = C::project(self);
189
190
        // SAFETY: `self`'s referent lives at a `NonNull` address, and is either
191
        // zero-sized or lives in an allocation. In either case, it does not
192
        // wrap around the address space [1], and so none of the addresses
193
        // contained in it or one-past-the-end of it are null.
194
        //
195
        // By invariant on `C: Project`, `C::project` is a provenance-preserving
196
        // projection which preserves or shrinks the set of referent bytes, so
197
        // `projected_raw` references a subset of `self`'s referent, and so it
198
        // cannot be null.
199
        //
200
        // [1] https://doc.rust-lang.org/1.92.0/std/ptr/index.html#allocation
201
0
        let projected_non_null = unsafe { NonNull::new_unchecked(projected_raw) };
202
203
        // SAFETY: As described in the preceding safety comment, `projected_raw`,
204
        // and thus `projected_non_null`, addresses a subset of `self`'s
205
        // referent. Thus, `projected_non_null` either:
206
        // - Addresses zero bytes or,
207
        // - Addresses a subset of the referent of `self`. In this case, `self`
208
        //   has provenance for its referent, which lives in an allocation.
209
        //   Since `projected_non_null` was constructed using a sequence of
210
        //   provenance-preserving operations, it also has provenance for its
211
        //   referent and that referent lives in an allocation. By invariant on
212
        //   `self`, that allocation lives for `'a`.
213
0
        unsafe { PtrInner::new(projected_non_null) }
214
0
    }
Unexecuted instantiation: <zerocopy::pointer::inner::_def::PtrInner<[half::binary16::f16]>>::project::<[half::binary16::f16], zerocopy::pointer::cast::IdCast>
Unexecuted instantiation: <zerocopy::pointer::inner::_def::PtrInner<[half::binary16::f16]>>::project::<[u16], zerocopy::layout::cast_from::CastFrom<[u16]>>
Unexecuted instantiation: <zerocopy::pointer::inner::_def::PtrInner<[u16]>>::project::<[u16], zerocopy::pointer::cast::IdCast>
215
}
216
217
#[allow(clippy::needless_lifetimes)]
218
impl<'a, T> PtrInner<'a, T>
219
where
220
    T: ?Sized + KnownLayout,
221
{
222
    /// Extracts the metadata of this `ptr`.
223
    #[inline]
224
    #[must_use]
225
    pub fn meta(self) -> MetadataOf<T> {
226
        let meta = T::pointer_to_metadata(self.as_ptr());
227
        // SAFETY: By invariant on `PtrInner`, `self.as_non_null()` addresses no
228
        // more than `isize::MAX` bytes.
229
        unsafe { MetadataOf::new_unchecked(meta) }
230
    }
231
232
    /// Produces a `PtrInner` with the same address and provenance as `self` but
233
    /// the given `meta`.
234
    ///
235
    /// # Safety
236
    ///
237
    /// The caller promises that if `self`'s referent is not zero sized, then
238
    /// a pointer constructed from its address with the given `meta` metadata
239
    /// will address a subset of the allocation pointed to by `self`.
240
    #[inline]
241
    #[must_use]
242
    pub unsafe fn with_meta(self, meta: T::PointerMetadata) -> Self
243
    where
244
        T: KnownLayout,
245
    {
246
        let raw = T::raw_from_ptr_len(self.as_non_null().cast(), meta);
247
248
        // SAFETY:
249
        //
250
        // Lemma 0: `raw` either addresses zero bytes, or addresses a subset of
251
        //          the allocation pointed to by `self` and has the same
252
        //          provenance as `self`. Proof: `raw` is constructed using
253
        //          provenance-preserving operations, and the caller has
254
        //          promised that, if `self`'s referent is not zero-sized, the
255
        //          resulting pointer addresses a subset of the allocation
256
        //          pointed to by `self`.
257
        //
258
        // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
259
        //    zero sized, then `ptr` is derived from some valid Rust allocation,
260
        //    `A`.
261
        // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
262
        //    zero sized, then `ptr` has valid provenance for `A`.
263
        // 2. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
264
        //    zero sized, then `ptr` addresses a byte range which is entirely
265
        //    contained in `A`.
266
        // 3. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte
267
        //    range whose length fits in an `isize`.
268
        // 4. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte
269
        //    range which does not wrap around the address space.
270
        // 5. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
271
        //    zero sized, then `A` is guaranteed to live for at least `'a`.
272
        unsafe { PtrInner::new(raw) }
273
    }
274
}
275
276
#[allow(clippy::needless_lifetimes)]
277
impl<'a, T> PtrInner<'a, T>
278
where
279
    T: ?Sized + KnownLayout<PointerMetadata = usize>,
280
{
281
    /// Splits `T` in two.
282
    ///
283
    /// # Safety
284
    ///
285
    /// The caller promises that:
286
    ///  - `l_len.get() <= self.meta()`.
287
    ///
288
    /// ## (Non-)Overlap
289
    ///
290
    /// Given `let (left, right) = ptr.split_at(l_len)`, it is guaranteed that
291
    /// `left` and `right` are contiguous and non-overlapping if
292
    /// the left part has no trailing padding. This is true for all `[T]`.
293
    ///
294
    /// Any trailing padding in the left part begins at the right part's
295
    /// starting address and may overlap its referent.
296
    #[inline]
297
    #[must_use]
298
    pub unsafe fn split_at_unchecked(
299
        self,
300
        l_len: crate::util::MetadataOf<T>,
301
    ) -> (Self, PtrInner<'a, [T::Elem]>)
302
    where
303
        T: SplitAt,
304
    {
305
        let l_len = l_len.get();
306
307
        // SAFETY: The caller promises that `l_len.get() <= self.meta()`.
308
        // Trivially, `0 <= l_len`.
309
        let left = unsafe { self.with_meta(l_len) };
310
311
        let right = self.trailing_slice();
312
        // SAFETY: The caller promises that `l_len <= self.meta() = slf.meta()`.
313
        // Trivially, `slf.meta() <= slf.meta()`.
314
        let right = unsafe { right.slice_unchecked(l_len..self.meta().get()) };
315
316
        // SAFETY: If the left part has no trailing padding, then `left` and
317
        // `right` are non-overlapping. Proof: `left` has `l_len` trailing
318
        // elements, and `right` starts at element `l_len` of the original
319
        // trailing slice. Without padding after `left`'s final element, no
320
        // byte is referred to by both pointers.
321
        //
322
        // Any trailing padding in `left` begins at `right`'s starting
323
        // address. If `right` is nonzero sized, the referents overlap.
324
        (left, right)
325
    }
326
327
    /// Produces the trailing slice of `self` using `T::Elem` as its element
328
    /// representation.
329
    #[inline]
330
    #[must_use]
331
    pub fn trailing_slice(self) -> PtrInner<'a, [T::Elem]>
332
    where
333
        T: SplitAt,
334
    {
335
        let offset = crate::trailing_slice_layout::<T>().offset;
336
337
        let bytes = self.as_non_null().cast::<u8>().as_ptr();
338
339
        // SAFETY:
340
        // - By invariant on `T: KnownLayout`, `T::LAYOUT` describes `T`'s
341
        //   layout. `offset` is the offset of the trailing slice within `T`,
342
        //   which is by definition in-bounds or one byte past the end of any
343
        //   `T`, regardless of metadata. By invariant on `PtrInner`, `self`
344
        //   (and thus `bytes`) points to a byte range of size `<= isize::MAX`,
345
        //   and so `offset <= isize::MAX`. Since `size_of::<u8>() == 1`,
346
        //   `offset * size_of::<u8>() <= isize::MAX`.
347
        // - If `offset > 0`, then by invariant on `PtrInner`, `self` (and thus
348
        //   `bytes`) points to a byte range entirely contained within the same
349
        //   allocated object as `self`. As explained above, this offset results
350
        //   in a pointer to or one byte past the end of this allocated object.
351
        let bytes = unsafe { bytes.add(offset) };
352
353
        // SAFETY: By the preceding safety argument, `bytes` is within or one
354
        // byte past the end of the same allocated object as `self`, which
355
        // ensures that it is non-null.
356
        let bytes = unsafe { NonNull::new_unchecked(bytes) };
357
358
        let ptr = KnownLayout::raw_from_ptr_len(bytes, self.meta().get());
359
360
        // SAFETY:
361
        // 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from
362
        //    some valid Rust allocation, `A`, because `ptr` is derived from
363
        //    the same allocated object as `self`.
364
        // 1. If `ptr`'s referent is not zero sized, then `ptr` has valid
365
        //    provenance for `A` because `raw` is derived from the same
366
        //    allocated object as `self` via provenance-preserving operations.
367
        // 2. `T: SplitAt` guarantees that `T::Elem` has the size of the actual
368
        //    trailing element. The new slice has the same length and start as
369
        //    the original trailing slice, so it covers the same byte range.
370
        //    If nonzero sized, that range is entirely contained in `A`.
371
        // 3. `ptr` addresses a byte range whose length fits in an `isize`, by
372
        //    consequence of #2.
373
        // 4. `ptr` addresses a byte range which does not wrap around the
374
        //    address space, by consequence of #2.
375
        // 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to
376
        //    live for at least `'a`, because `ptr` is derived from `self`.
377
        unsafe { PtrInner::new(ptr) }
378
    }
379
}
380
381
#[allow(clippy::needless_lifetimes)]
382
impl<'a, T> PtrInner<'a, [T]> {
383
    /// Creates a pointer which addresses the given `range` of self.
384
    ///
385
    /// # Safety
386
    ///
387
    /// `range` is a valid range (`start <= end`) and `end <= self.meta()`.
388
    #[inline]
389
    #[must_use]
390
    pub unsafe fn slice_unchecked(self, range: Range<usize>) -> Self {
391
        let base = self.as_non_null().cast::<T>().as_ptr();
392
393
        // SAFETY: The caller promises that `start <= end <= self.meta()`. By
394
        // invariant, if `self`'s referent is not zero-sized, then `self` refers
395
        // to a byte range which is contained within a single allocation, which
396
        // is no more than `isize::MAX` bytes long, and which does not wrap
397
        // around the address space. Thus, this pointer arithmetic remains
398
        // in-bounds of the same allocation, and does not wrap around the
399
        // address space. The offset (in bytes) does not overflow `isize`.
400
        //
401
        // If `self`'s referent is zero-sized, then these conditions are
402
        // trivially satisfied.
403
        let base = unsafe { base.add(range.start) };
404
405
        // SAFETY: The caller promises that `start <= end`, and so this will not
406
        // underflow.
407
        #[allow(unstable_name_collisions)]
408
        let len = unsafe { range.end.unchecked_sub(range.start) };
409
410
        let ptr = core::ptr::slice_from_raw_parts_mut(base, len);
411
412
        // SAFETY: By invariant, `self`'s referent is either a ZST or lives
413
        // entirely in an allocation. `ptr` points inside of or one byte past
414
        // the end of that referent. Thus, in either case, `ptr` is non-null.
415
        let ptr = unsafe { NonNull::new_unchecked(ptr) };
416
417
        // SAFETY:
418
        //
419
        // Lemma 0: `ptr` addresses a subset of the bytes addressed by `self`,
420
        //          and has the same provenance. Proof: The caller guarantees
421
        //          that `start <= end <= self.meta()`. Thus, `base` is
422
        //          in-bounds of `self`, and `base + (end - start)` is also
423
        //          in-bounds of self. Finally, `ptr` is constructed using
424
        //          provenance-preserving operations.
425
        //
426
        // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
427
        //    zero sized, then `ptr` has valid provenance for its referent,
428
        //    which is entirely contained in some Rust allocation, `A`.
429
        // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
430
        //    zero sized, then `A` is guaranteed to live for at least `'a`.
431
        unsafe { PtrInner::new(ptr) }
432
    }
433
434
    /// Iteratively projects the elements `PtrInner<T>` from `PtrInner<[T]>`.
435
    #[inline]
436
    pub fn iter(&self) -> impl Iterator<Item = PtrInner<'a, T>> {
437
        // FIXME(#429): Once `NonNull::cast` documents that it preserves
438
        // provenance, cite those docs.
439
        let base = self.as_non_null().cast::<T>().as_ptr();
440
        (0..self.meta().get()).map(move |i| {
441
            // FIXME(https://github.com/rust-lang/rust/issues/74265): Use
442
            // `NonNull::get_unchecked_mut`.
443
444
            // SAFETY: If the following conditions are not satisfied
445
            // `pointer::cast` may induce Undefined Behavior [1]:
446
            //
447
            // > - The computed offset, `count * size_of::<T>()` bytes, must not
448
            // >   overflow `isize``.
449
            // > - If the computed offset is non-zero, then `self` must be
450
            // >   derived from a pointer to some allocated object, and the
451
            // >   entire memory range between `self` and the result must be in
452
            // >   bounds of that allocated object. In particular, this range
453
            // >   must not “wrap around” the edge of the address space.
454
            //
455
            // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add
456
            //
457
            // We satisfy both of these conditions here:
458
            // - By invariant on `Ptr`, `self` addresses a byte range whose
459
            //   length fits in an `isize`. Since `elem` is contained in `self`,
460
            //   the computed offset of `elem` must fit within `isize.`
461
            // - If the computed offset is non-zero, then this means that the
462
            //   referent is not zero-sized. In this case, `base` points to an
463
            //   allocated object (by invariant on `self`). Thus:
464
            //   - By contract, `self.meta()` accurately reflects the number of
465
            //     elements in the slice. `i` is in bounds of `c.meta()` by
466
            //     construction, and so the result of this addition cannot
467
            //     overflow past the end of the allocation referred to by `c`.
468
            //   - By invariant on `Ptr`, `self` addresses a byte range which
469
            //     does not wrap around the address space. Since `elem` is
470
            //     contained in `self`, the computed offset of `elem` must wrap
471
            //     around the address space.
472
            //
473
            // FIXME(#429): Once `pointer::add` documents that it preserves
474
            // provenance, cite those docs.
475
            let elem = unsafe { base.add(i) };
476
477
            // SAFETY: `elem` must not be null. `base` is constructed from a
478
            // `NonNull` pointer, and the addition that produces `elem` must not
479
            // overflow or wrap around, so `elem >= base > 0`.
480
            //
481
            // FIXME(#429): Once `NonNull::new_unchecked` documents that it
482
            // preserves provenance, cite those docs.
483
            let elem = unsafe { NonNull::new_unchecked(elem) };
484
485
            // SAFETY: The safety invariants of `Ptr::new` (see definition) are
486
            // satisfied:
487
            // 0. If `elem`'s referent is not zero sized, then `elem` has valid
488
            //    provenance for its referent, because it derived from `self`
489
            //    using a series of provenance-preserving operations, and
490
            //    because `self` has valid provenance for its referent. By the
491
            //    same argument, `elem`'s referent is entirely contained within
492
            //    the same allocated object as `self`'s referent.
493
            // 1. If `elem`'s referent is not zero sized, then the allocation of
494
            //    `elem` is guaranteed to live for at least `'a`, because `elem`
495
            //    is entirely contained in `self`, which lives for at least `'a`
496
            //    by invariant on `Ptr`.
497
            unsafe { PtrInner::new(elem) }
498
        })
499
    }
500
}
501
502
impl<'a, T, const N: usize> PtrInner<'a, [T; N]> {
503
    /// Casts this pointer-to-array into a slice.
504
    ///
505
    /// # Safety
506
    ///
507
    /// Callers may assume that the returned `PtrInner` references the same
508
    /// address and length as `self`.
509
    #[allow(clippy::wrong_self_convention)]
510
    #[inline]
511
    #[must_use]
512
    pub fn as_slice(self) -> PtrInner<'a, [T]> {
513
        let start = self.as_non_null().cast::<T>().as_ptr();
514
        let slice = core::ptr::slice_from_raw_parts_mut(start, N);
515
        // SAFETY: `slice` is not null, because it is derived from `start`
516
        // which is non-null.
517
        let slice = unsafe { NonNull::new_unchecked(slice) };
518
        // SAFETY: Lemma: In the following safety arguments, note that `slice`
519
        // is derived from `self` in two steps: first, by casting `self: [T; N]`
520
        // to `start: T`, then by constructing a pointer to a slice starting at
521
        // `start` of length `N`. As a result, `slice` references exactly the
522
        // same allocation as `self`, if any.
523
        //
524
        // 0. By the above lemma, if `slice`'s referent is not zero sized, then
525
        //    `slice` has the same referent as `self`. By invariant on `self`,
526
        //    this referent is entirely contained within some allocation, `A`.
527
        //    Because `slice` was constructed using provenance-preserving
528
        //    operations, it has provenance for its entire referent.
529
        // 1. By the above lemma, if `slice`'s referent is not zero sized, then
530
        //    `A` is guaranteed to live for at least `'a`, because it is derived
531
        //    from the same allocation as `self`, which, by invariant on
532
        //    `PtrInner`, lives for at least `'a`.
533
        unsafe { PtrInner::new(slice) }
534
    }
535
}
536
537
impl<'a> PtrInner<'a, [u8]> {
538
    /// Attempts to cast `self` to a `U` using the given cast type.
539
    ///
540
    /// If `U` is a slice DST and pointer metadata (`meta`) is provided, then
541
    /// the cast will only succeed if it would produce an object with the given
542
    /// metadata.
543
    ///
544
    /// Returns `None` if the resulting `U` would be invalidly-aligned, if no
545
    /// `U` can fit in `self`, or if the provided pointer metadata describes an
546
    /// invalid instance of `U`. On success, returns a pointer to the
547
    /// largest-possible `U` which fits in `self`.
548
    ///
549
    /// # Safety
550
    ///
551
    /// The caller may assume that this implementation is correct, and may rely
552
    /// on that assumption for the soundness of their code. In particular, the
553
    /// caller may assume that, if `try_cast_into` returns `Some((ptr,
554
    /// remainder))`, then `ptr` and `remainder` refer to non-overlapping byte
555
    /// ranges within `self`, and that `ptr` and `remainder` entirely cover
556
    /// `self`. Finally:
557
    /// - If this is a prefix cast, `ptr` has the same address as `self`.
558
    /// - If this is a suffix cast, `remainder` has the same address as `self`.
559
    #[inline]
560
    pub fn try_cast_into<U>(
561
        self,
562
        cast_type: CastType,
563
        meta: Option<U::PointerMetadata>,
564
    ) -> Result<(PtrInner<'a, U>, PtrInner<'a, [u8]>), CastError<Self, U>>
565
    where
566
        U: 'a + ?Sized + KnownLayout,
567
    {
568
        // PANICS: By invariant, the byte range addressed by
569
        // `self.as_non_null()` does not wrap around the address space. This
570
        // implies that the sum of the address (represented as a `usize`) and
571
        // length do not overflow `usize`, as required by
572
        // `validate_cast_and_convert_metadata`. Thus, this call to
573
        // `validate_cast_and_convert_metadata` will only panic if `U` is a DST
574
        // whose trailing slice element is zero-sized.
575
        let maybe_metadata = MetadataOf::<U>::validate_cast_and_convert_metadata(
576
            AsAddress::addr(self.as_ptr()),
577
            self.meta(),
578
            cast_type,
579
            meta,
580
        );
581
582
        let (elems, split_at) = match maybe_metadata {
583
            Ok((elems, split_at)) => (elems, split_at),
584
            Err(MetadataCastError::Alignment) => {
585
                // SAFETY: Since `validate_cast_and_convert_metadata` returned
586
                // an alignment error, `U` must have an alignment requirement
587
                // greater than one.
588
                let err = unsafe { AlignmentError::<_, U>::new_unchecked(self) };
589
                return Err(CastError::Alignment(err));
590
            }
591
            Err(MetadataCastError::Size) => return Err(CastError::Size(SizeError::new(self))),
592
        };
593
594
        // SAFETY: `validate_cast_and_convert_metadata` promises to return
595
        // `split_at <= self.meta()`.
596
        //
597
        // Lemma 0: `l_slice` and `r_slice` are non-overlapping. Proof: By
598
        // contract on `PtrInner::split_at_unchecked`, the produced `PtrInner`s
599
        // are always non-overlapping if `self` is a `[T]`; here it is a `[u8]`.
600
        let (l_slice, r_slice) = unsafe { self.split_at_unchecked(split_at) };
601
602
        let (target, remainder) = match cast_type {
603
            CastType::Prefix => (l_slice, r_slice),
604
            CastType::Suffix => (r_slice, l_slice),
605
        };
606
607
        let base = target.as_non_null().cast::<u8>();
608
609
        let ptr = U::raw_from_ptr_len(base, elems.get());
610
611
        // SAFETY:
612
        // 0. By invariant, if `target`'s referent is not zero sized, then
613
        //    `target` has provenance valid for some Rust allocation, `A`.
614
        //    Because `ptr` is derived from `target` via provenance-preserving
615
        //    operations, `ptr` will also have provenance valid for its entire
616
        //    referent.
617
        // 1. `validate_cast_and_convert_metadata` promises that the object
618
        //    described by `elems` and `split_at` lives at a byte range which is
619
        //    a subset of the input byte range. Thus, by invariant, if
620
        //    `target`'s referent is not zero sized, then `target` refers to an
621
        //    allocation which is guaranteed to live for at least `'a`, and thus
622
        //    so does `ptr`.
623
        Ok((unsafe { PtrInner::new(ptr) }, remainder))
624
    }
625
}
626
627
#[cfg(test)]
628
mod tests {
629
    use super::*;
630
    use crate::*;
631
632
    #[test]
633
    fn test_meta() {
634
        let arr = [1; 16];
635
        let dst = <[u8]>::ref_from_bytes(&arr[..]).unwrap();
636
        let ptr = PtrInner::from_ref(dst);
637
        assert_eq!(ptr.meta().get(), 16);
638
639
        // SAFETY: 8 is less than 16
640
        let ptr = unsafe { ptr.with_meta(8) };
641
642
        assert_eq!(ptr.meta().get(), 8);
643
    }
644
645
    #[test]
646
    fn test_split_at() {
647
        fn test_split_at<const OFFSET: usize, const BUFFER_SIZE: usize>() {
648
            #[derive(FromBytes, KnownLayout, SplitAt, Immutable)]
649
            #[repr(C)]
650
            struct SliceDst<const OFFSET: usize> {
651
                prefix: [u8; OFFSET],
652
                trailing: [u8],
653
            }
654
655
            let n: usize = BUFFER_SIZE - OFFSET;
656
            let arr = [1; BUFFER_SIZE];
657
            let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap();
658
            let ptr = PtrInner::from_ref(dst);
659
            for i in 0..=n {
660
                assert_eq!(ptr.meta().get(), n);
661
                // SAFETY: `i` is in bounds by construction.
662
                let i = unsafe { MetadataOf::new_unchecked(i) };
663
                // SAFETY: `i` is in bounds by construction.
664
                let (l, r) = unsafe { ptr.split_at_unchecked(i) };
665
                // SAFETY: Points to a valid value by construction.
666
                #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)]
667
                // Clippy false positive
668
                let l_sum: usize = l
669
                    .trailing_slice()
670
                    .iter()
671
                    .map(
672
                        #[inline(always)]
673
                        |ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize,
674
                    )
675
                    .sum();
676
                // SAFETY: Points to a valid value by construction.
677
                #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)]
678
                // Clippy false positive
679
                let r_sum: usize = r
680
                    .iter()
681
                    .map(
682
                        #[inline(always)]
683
                        |ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize,
684
                    )
685
                    .sum();
686
                assert_eq!(l_sum, i.get());
687
                assert_eq!(r_sum, n - i.get());
688
                assert_eq!(l_sum + r_sum, n);
689
            }
690
        }
691
692
        test_split_at::<0, 16>();
693
        test_split_at::<1, 17>();
694
        test_split_at::<2, 18>();
695
    }
696
697
    #[test]
698
    fn test_trailing_slice() {
699
        fn test_trailing_slice<const OFFSET: usize, const BUFFER_SIZE: usize>() {
700
            #[derive(FromBytes, KnownLayout, SplitAt, Immutable)]
701
            #[repr(C)]
702
            struct SliceDst<const OFFSET: usize> {
703
                prefix: [u8; OFFSET],
704
                trailing: [u8],
705
            }
706
707
            let n: usize = BUFFER_SIZE - OFFSET;
708
            let arr = [1; BUFFER_SIZE];
709
            let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap();
710
            let ptr = PtrInner::from_ref(dst);
711
712
            assert_eq!(ptr.meta().get(), n);
713
            let trailing = ptr.trailing_slice();
714
            assert_eq!(trailing.meta().get(), n);
715
716
            assert_eq!(
717
                // SAFETY: We assume this to be sound for the sake of this test,
718
                // which will fail, here, in miri, if the safety precondition of
719
                // `offset_of` is not satisfied.
720
                unsafe {
721
                    #[allow(clippy::as_conversions)]
722
                    let offset = (trailing.as_ptr() as *mut u8).offset_from(ptr.as_ptr() as *mut _);
723
                    offset
724
                },
725
                isize::try_from(OFFSET).unwrap(),
726
            );
727
728
            // SAFETY: Points to a valid value by construction.
729
            #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)]
730
            // Clippy false positive
731
            let trailing: usize = trailing
732
                .iter()
733
                .map(|ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize)
734
                .sum();
735
736
            assert_eq!(trailing, n);
737
        }
738
739
        test_trailing_slice::<0, 16>();
740
        test_trailing_slice::<1, 17>();
741
        test_trailing_slice::<2, 18>();
742
    }
743
    #[test]
744
    fn test_ptr_inner_clone() {
745
        let mut x = 0u8;
746
        let p = PtrInner::from_mut(&mut x);
747
        #[allow(clippy::clone_on_copy)]
748
        let p2 = p.clone();
749
        assert_eq!(p.as_non_null(), p2.as_non_null());
750
    }
751
}