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