zerocopy/pointer/inner.rs
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
11use core::{marker::PhantomData, ops::Range, ptr::NonNull};
12
13pub use _def::PtrInner;
14
15#[allow(unused_imports)]
16use crate::util::polyfills::NumExt as _;
17use crate::{
18 layout::{CastType, MetadataCastError},
19 pointer::cast,
20 util::AsAddress,
21 AlignmentError, CastError, KnownLayout, MetadataOf, SizeError, SplitAt,
22};
23
24mod _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 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 Self { ptr, _marker: PhantomData }
102 }
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 pub const fn as_non_null(&self) -> NonNull<T> {
112 self.ptr
113 }
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 pub const fn as_ptr(&self) -> *mut T {
123 self.ptr.as_ptr()
124 }
125 }
126}
127
128impl<'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 pub fn from_mut(ptr: &'a mut T) -> Self {
158 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 unsafe { Self::new(ptr) }
179 }
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 pub fn project<U: ?Sized, C: cast::Project<T, U>>(self) -> PtrInner<'a, U> {
188 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 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 unsafe { PtrInner::new(projected_non_null) }
214 }
215}
216
217#[allow(clippy::needless_lifetimes)]
218impl<'a, T> PtrInner<'a, T>
219where
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)]
277impl<'a, T> PtrInner<'a, T>
278where
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)]
382impl<'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
502impl<'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
537impl<'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)]
628mod 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}