zerocopy/pointer/
inner.rs

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