 9bda913e36
			
		
	
	
		9bda913e36
		
			
		
	
	
	
	
		
			
			# Objective - fix #12853 - Make `Table::allocate` faster ## Solution The PR consists of multiple steps: 1) For the component data: create a new data-structure that's similar to `BlobVec` but doesn't store `len` & `capacity` inside of it: "BlobArray" (name suggestions welcome) 2) For the `Tick` data: create a new data-structure that's similar to `ThinSlicePtr` but supports dynamic reallocation: "ThinArrayPtr" (name suggestions welcome) 3) Create a new data-structure that's very similar to `Column` that doesn't store `len` & `capacity` inside of it: "ThinColumn" 4) Adjust the `Table` implementation to use `ThinColumn` instead of `Column` The result is that only one set of `len` & `capacity` is stored in `Table`, in `Table::entities` ### Notes Regarding Performance Apart from shaving off some excess memory in `Table`, the changes have also brought noteworthy performance improvements: The previous implementation relied on `Vec::reserve` & `BlobVec::reserve`, but that redundantly repeated the same if statement (`capacity` == `len`). Now that check could be made at the `Table` level because the capacity and length of all the columns are synchronized; saving N branches per allocation. The result is a respectable performance improvement per every `Table::reserve` (and subsequently `Table::allocate`) call. I'm hesitant to give exact numbers because I don't have a lot of experience in profiling and benchmarking, but these are the results I got so far: *`add_remove_big/table` benchmark after the implementation:*  *`add_remove_big/table` benchmark in main branch (measured in comparison to the implementation):*  *`add_remove_very_big/table` benchmark after the implementation:*  *`add_remove_very_big/table` benchmark in main branch (measured in comparison to the implementation):*  cc @james7132 to verify --- ## Changelog - New data-structure that's similar to `BlobVec` but doesn't store `len` & `capacity` inside of it: `BlobArray` - New data-structure that's similar to `ThinSlicePtr` but supports dynamic allocation:`ThinArrayPtr` - New data-structure that's very similar to `Column` that doesn't store `len` & `capacity` inside of it: `ThinColumn` - Adjust the `Table` implementation to use `ThinColumn` instead of `Column` - New benchmark: `add_remove_very_big` to benchmark the performance of spawning a lot of entities with a lot of components (15) each ## Migration Guide `Table` now uses `ThinColumn` instead of `Column`. That means that methods that previously returned `Column`, will now return `ThinColumn` instead. `ThinColumn` has a much more limited and low-level API, but you can still achieve the same things in `ThinColumn` as you did in `Column`. For example, instead of calling `Column::get_added_tick`, you'd call `ThinColumn::get_added_ticks_slice` and index it to get the specific added tick. --------- Co-authored-by: James Liu <contact@jamessliu.com>
		
			
				
	
	
		
			631 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			631 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| #![doc = include_str!("../README.md")]
 | |
| #![no_std]
 | |
| #![cfg_attr(docsrs, feature(doc_auto_cfg))]
 | |
| #![allow(unsafe_code)]
 | |
| #![doc(
 | |
|     html_logo_url = "https://bevyengine.org/assets/icon.png",
 | |
|     html_favicon_url = "https://bevyengine.org/assets/icon.png"
 | |
| )]
 | |
| 
 | |
| use core::{
 | |
|     cell::UnsafeCell,
 | |
|     fmt::{self, Formatter, Pointer},
 | |
|     marker::PhantomData,
 | |
|     mem::ManuallyDrop,
 | |
|     num::NonZeroUsize,
 | |
|     ptr::NonNull,
 | |
| };
 | |
| 
 | |
| /// Used as a type argument to [`Ptr`], [`PtrMut`] and [`OwningPtr`] to specify that the pointer is aligned.
 | |
| #[derive(Copy, Clone)]
 | |
| pub struct Aligned;
 | |
| 
 | |
| /// Used as a type argument to [`Ptr`], [`PtrMut`] and [`OwningPtr`] to specify that the pointer is not aligned.
 | |
| #[derive(Copy, Clone)]
 | |
| pub struct Unaligned;
 | |
| 
 | |
| /// Trait that is only implemented for [`Aligned`] and [`Unaligned`] to work around the lack of ability
 | |
| /// to have const generics of an enum.
 | |
| pub trait IsAligned: sealed::Sealed {}
 | |
| impl IsAligned for Aligned {}
 | |
| impl IsAligned for Unaligned {}
 | |
| 
 | |
| mod sealed {
 | |
|     pub trait Sealed {}
 | |
|     impl Sealed for super::Aligned {}
 | |
|     impl Sealed for super::Unaligned {}
 | |
| }
 | |
| 
 | |
| /// A newtype around [`NonNull`] that only allows conversion to read-only borrows or pointers.
 | |
| ///
 | |
| /// This type can be thought of as the `*const T` to [`NonNull<T>`]'s `*mut T`.
 | |
| #[repr(transparent)]
 | |
| pub struct ConstNonNull<T: ?Sized>(NonNull<T>);
 | |
| 
 | |
| impl<T: ?Sized> ConstNonNull<T> {
 | |
|     /// Creates a new `ConstNonNull` if `ptr` is non-null.
 | |
|     ///
 | |
|     /// # Examples
 | |
|     ///
 | |
|     /// ```
 | |
|     /// use bevy_ptr::ConstNonNull;
 | |
|     ///
 | |
|     /// let x = 0u32;
 | |
|     /// let ptr = ConstNonNull::<u32>::new(&x as *const _).expect("ptr is null!");
 | |
|     ///
 | |
|     /// if let Some(ptr) = ConstNonNull::<u32>::new(std::ptr::null()) {
 | |
|     ///     unreachable!();
 | |
|     /// }
 | |
|     /// ```
 | |
|     pub fn new(ptr: *const T) -> Option<Self> {
 | |
|         NonNull::new(ptr.cast_mut()).map(Self)
 | |
|     }
 | |
| 
 | |
|     /// Creates a new `ConstNonNull`.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     ///
 | |
|     /// `ptr` must be non-null.
 | |
|     ///
 | |
|     /// # Examples
 | |
|     ///
 | |
|     /// ```
 | |
|     /// use bevy_ptr::ConstNonNull;
 | |
|     ///
 | |
|     /// let x = 0u32;
 | |
|     /// let ptr = unsafe { ConstNonNull::new_unchecked(&x as *const _) };
 | |
|     /// ```
 | |
|     ///
 | |
|     /// *Incorrect* usage of this function:
 | |
|     ///
 | |
|     /// ```rust,no_run
 | |
|     /// use bevy_ptr::ConstNonNull;
 | |
|     ///
 | |
|     /// // NEVER DO THAT!!! This is undefined behavior. ⚠️
 | |
|     /// let ptr = unsafe { ConstNonNull::<u32>::new_unchecked(std::ptr::null()) };
 | |
|     /// ```
 | |
|     pub const unsafe fn new_unchecked(ptr: *const T) -> Self {
 | |
|         // SAFETY: This function's safety invariants are identical to `NonNull::new_unchecked`
 | |
|         // The caller must satisfy all of them.
 | |
|         unsafe { Self(NonNull::new_unchecked(ptr.cast_mut())) }
 | |
|     }
 | |
| 
 | |
|     /// Returns a shared reference to the value.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     ///
 | |
|     /// When calling this method, you have to ensure that all of the following is true:
 | |
|     ///
 | |
|     /// * The pointer must be properly aligned.
 | |
|     ///
 | |
|     /// * It must be "dereferenceable" in the sense defined in [the module documentation].
 | |
|     ///
 | |
|     /// * The pointer must point to an initialized instance of `T`.
 | |
|     ///
 | |
|     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
 | |
|     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
 | |
|     ///   In particular, while this reference exists, the memory the pointer points to must
 | |
|     ///   not get mutated (except inside `UnsafeCell`).
 | |
|     ///
 | |
|     /// This applies even if the result of this method is unused!
 | |
|     /// (The part about being initialized is not yet fully decided, but until
 | |
|     /// it is, the only safe approach is to ensure that they are indeed initialized.)
 | |
|     ///
 | |
|     /// # Examples
 | |
|     ///
 | |
|     /// ```
 | |
|     /// use bevy_ptr::ConstNonNull;
 | |
|     ///
 | |
|     /// let mut x = 0u32;
 | |
|     /// let ptr = ConstNonNull::new(&mut x as *mut _).expect("ptr is null!");
 | |
|     ///
 | |
|     /// let ref_x = unsafe { ptr.as_ref() };
 | |
|     /// println!("{ref_x}");
 | |
|     /// ```
 | |
|     ///
 | |
|     /// [the module documentation]: core::ptr#safety
 | |
|     #[inline]
 | |
|     pub unsafe fn as_ref<'a>(&self) -> &'a T {
 | |
|         // SAFETY: This function's safety invariants are identical to `NonNull::as_ref`
 | |
|         // The caller must satisfy all of them.
 | |
|         unsafe { self.0.as_ref() }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<T: ?Sized> From<NonNull<T>> for ConstNonNull<T> {
 | |
|     fn from(value: NonNull<T>) -> ConstNonNull<T> {
 | |
|         ConstNonNull(value)
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'a, T: ?Sized> From<&'a T> for ConstNonNull<T> {
 | |
|     fn from(value: &'a T) -> ConstNonNull<T> {
 | |
|         ConstNonNull(NonNull::from(value))
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'a, T: ?Sized> From<&'a mut T> for ConstNonNull<T> {
 | |
|     fn from(value: &'a mut T) -> ConstNonNull<T> {
 | |
|         ConstNonNull(NonNull::from(value))
 | |
|     }
 | |
| }
 | |
| /// Type-erased borrow of some unknown type chosen when constructing this type.
 | |
| ///
 | |
| /// This type tries to act "borrow-like" which means that:
 | |
| /// - It should be considered immutable: its target must not be changed while this pointer is alive.
 | |
| /// - It must always points to a valid value of whatever the pointee type is.
 | |
| /// - The lifetime `'a` accurately represents how long the pointer is valid for.
 | |
| /// - Must be sufficiently aligned for the unknown pointee type.
 | |
| ///
 | |
| /// It may be helpful to think of this type as similar to `&'a dyn Any` but without
 | |
| /// the metadata and able to point to data that does not correspond to a Rust type.
 | |
| #[derive(Copy, Clone, Debug)]
 | |
| #[repr(transparent)]
 | |
| pub struct Ptr<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a u8, A)>);
 | |
| 
 | |
| /// Type-erased mutable borrow of some unknown type chosen when constructing this type.
 | |
| ///
 | |
| /// This type tries to act "borrow-like" which means that:
 | |
| /// - Pointer is considered exclusive and mutable. It cannot be cloned as this would lead to
 | |
| ///   aliased mutability.
 | |
| /// - It must always points to a valid value of whatever the pointee type is.
 | |
| /// - The lifetime `'a` accurately represents how long the pointer is valid for.
 | |
| /// - Must be sufficiently aligned for the unknown pointee type.
 | |
| ///
 | |
| /// It may be helpful to think of this type as similar to `&'a mut dyn Any` but without
 | |
| /// the metadata and able to point to data that does not correspond to a Rust type.
 | |
| #[derive(Debug)]
 | |
| #[repr(transparent)]
 | |
| pub struct PtrMut<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a mut u8, A)>);
 | |
| 
 | |
| /// Type-erased Box-like pointer to some unknown type chosen when constructing this type.
 | |
| /// Conceptually represents ownership of whatever data is being pointed to and so is
 | |
| /// responsible for calling its `Drop` impl. This pointer is _not_ responsible for freeing
 | |
| /// the memory pointed to by this pointer as it may be pointing to an element in a `Vec` or
 | |
| /// to a local in a function etc.
 | |
| ///
 | |
| /// This type tries to act "borrow-like" like which means that:
 | |
| /// - Pointer should be considered exclusive and mutable. It cannot be cloned as this would lead
 | |
| ///   to aliased mutability and potentially use after free bugs.
 | |
| /// - It must always points to a valid value of whatever the pointee type is.
 | |
| /// - The lifetime `'a` accurately represents how long the pointer is valid for.
 | |
| /// - Must be sufficiently aligned for the unknown pointee type.
 | |
| ///
 | |
| /// It may be helpful to think of this type as similar to `&'a mut ManuallyDrop<dyn Any>` but
 | |
| /// without the metadata and able to point to data that does not correspond to a Rust type.
 | |
| #[derive(Debug)]
 | |
| #[repr(transparent)]
 | |
| pub struct OwningPtr<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a mut u8, A)>);
 | |
| 
 | |
| macro_rules! impl_ptr {
 | |
|     ($ptr:ident) => {
 | |
|         impl<'a> $ptr<'a, Aligned> {
 | |
|             /// Removes the alignment requirement of this pointer
 | |
|             pub fn to_unaligned(self) -> $ptr<'a, Unaligned> {
 | |
|                 $ptr(self.0, PhantomData)
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         impl<'a, A: IsAligned> From<$ptr<'a, A>> for NonNull<u8> {
 | |
|             fn from(ptr: $ptr<'a, A>) -> Self {
 | |
|                 ptr.0
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         impl<A: IsAligned> $ptr<'_, A> {
 | |
|             /// Calculates the offset from a pointer.
 | |
|             /// As the pointer is type-erased, there is no size information available. The provided
 | |
|             /// `count` parameter is in raw bytes.
 | |
|             ///
 | |
|             /// *See also: [`ptr::offset`][ptr_offset]*
 | |
|             ///
 | |
|             /// # Safety
 | |
|             /// - The offset cannot make the existing ptr null, or take it out of bounds for its allocation.
 | |
|             /// - If the `A` type parameter is [`Aligned`] then the offset must not make the resulting pointer
 | |
|             ///   be unaligned for the pointee type.
 | |
|             /// - The value pointed by the resulting pointer must outlive the lifetime of this pointer.
 | |
|             ///
 | |
|             /// [ptr_offset]: https://doc.rust-lang.org/std/primitive.pointer.html#method.offset
 | |
|             #[inline]
 | |
|             pub unsafe fn byte_offset(self, count: isize) -> Self {
 | |
|                 Self(
 | |
|                     // SAFETY: The caller upholds safety for `offset` and ensures the result is not null.
 | |
|                     unsafe { NonNull::new_unchecked(self.as_ptr().offset(count)) },
 | |
|                     PhantomData,
 | |
|                 )
 | |
|             }
 | |
| 
 | |
|             /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
 | |
|             /// As the pointer is type-erased, there is no size information available. The provided
 | |
|             /// `count` parameter is in raw bytes.
 | |
|             ///
 | |
|             /// *See also: [`ptr::add`][ptr_add]*
 | |
|             ///
 | |
|             /// # Safety
 | |
|             /// - The offset cannot make the existing ptr null, or take it out of bounds for its allocation.
 | |
|             /// - If the `A` type parameter is [`Aligned`] then the offset must not make the resulting pointer
 | |
|             ///   be unaligned for the pointee type.
 | |
|             /// - The value pointed by the resulting pointer must outlive the lifetime of this pointer.
 | |
|             ///
 | |
|             /// [ptr_add]: https://doc.rust-lang.org/std/primitive.pointer.html#method.add
 | |
|             #[inline]
 | |
|             pub unsafe fn byte_add(self, count: usize) -> Self {
 | |
|                 Self(
 | |
|                     // SAFETY: The caller upholds safety for `add` and ensures the result is not null.
 | |
|                     unsafe { NonNull::new_unchecked(self.as_ptr().add(count)) },
 | |
|                     PhantomData,
 | |
|                 )
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         impl<A: IsAligned> Pointer for $ptr<'_, A> {
 | |
|             #[inline]
 | |
|             fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
 | |
|                 Pointer::fmt(&self.0, f)
 | |
|             }
 | |
|         }
 | |
|     };
 | |
| }
 | |
| 
 | |
| impl_ptr!(Ptr);
 | |
| impl_ptr!(PtrMut);
 | |
| impl_ptr!(OwningPtr);
 | |
| 
 | |
| impl<'a, A: IsAligned> Ptr<'a, A> {
 | |
|     /// Creates a new instance from a raw pointer.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// - `inner` must point to valid value of whatever the pointee type is.
 | |
|     /// - If the `A` type parameter is [`Aligned`] then `inner` must be sufficiently aligned for the pointee type.
 | |
|     /// - `inner` must have correct provenance to allow reads of the pointee type.
 | |
|     /// - The lifetime `'a` must be constrained such that this [`Ptr`] will stay valid and nothing
 | |
|     ///   can mutate the pointee while this [`Ptr`] is live except through an [`UnsafeCell`].
 | |
|     #[inline]
 | |
|     pub unsafe fn new(inner: NonNull<u8>) -> Self {
 | |
|         Self(inner, PhantomData)
 | |
|     }
 | |
| 
 | |
|     /// Transforms this [`Ptr`] into an [`PtrMut`]
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// Another [`PtrMut`] for the same [`Ptr`] must not be created until the first is dropped.
 | |
|     #[inline]
 | |
|     pub unsafe fn assert_unique(self) -> PtrMut<'a, A> {
 | |
|         PtrMut(self.0, PhantomData)
 | |
|     }
 | |
| 
 | |
|     /// Transforms this [`Ptr<T>`] into a `&T` with the same lifetime
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// - `T` must be the erased pointee type for this [`Ptr`].
 | |
|     /// - If the type parameter `A` is [`Unaligned`] then this pointer must be sufficiently aligned
 | |
|     ///   for the pointee type `T`.
 | |
|     #[inline]
 | |
|     pub unsafe fn deref<T>(self) -> &'a T {
 | |
|         let ptr = self.as_ptr().cast::<T>().debug_ensure_aligned();
 | |
|         // SAFETY: The caller ensures the pointee is of type `T` and the pointer can be dereferenced.
 | |
|         unsafe { &*ptr }
 | |
|     }
 | |
| 
 | |
|     /// Gets the underlying pointer, erasing the associated lifetime.
 | |
|     ///
 | |
|     /// If possible, it is strongly encouraged to use [`deref`](Self::deref) over this function,
 | |
|     /// as it retains the lifetime.
 | |
|     #[inline]
 | |
|     #[allow(clippy::wrong_self_convention)]
 | |
|     pub fn as_ptr(self) -> *mut u8 {
 | |
|         self.0.as_ptr()
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'a, T: ?Sized> From<&'a T> for Ptr<'a> {
 | |
|     #[inline]
 | |
|     fn from(val: &'a T) -> Self {
 | |
|         // SAFETY: The returned pointer has the same lifetime as the passed reference.
 | |
|         // Access is immutable.
 | |
|         unsafe { Self::new(NonNull::from(val).cast()) }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'a, A: IsAligned> PtrMut<'a, A> {
 | |
|     /// Creates a new instance from a raw pointer.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// - `inner` must point to valid value of whatever the pointee type is.
 | |
|     /// - If the `A` type parameter is [`Aligned`] then `inner` must be sufficiently aligned for the pointee type.
 | |
|     /// - `inner` must have correct provenance to allow read and writes of the pointee type.
 | |
|     /// - The lifetime `'a` must be constrained such that this [`PtrMut`] will stay valid and nothing
 | |
|     ///   else can read or mutate the pointee while this [`PtrMut`] is live.
 | |
|     #[inline]
 | |
|     pub unsafe fn new(inner: NonNull<u8>) -> Self {
 | |
|         Self(inner, PhantomData)
 | |
|     }
 | |
| 
 | |
|     /// Transforms this [`PtrMut`] into an [`OwningPtr`]
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// Must have right to drop or move out of [`PtrMut`].
 | |
|     #[inline]
 | |
|     pub unsafe fn promote(self) -> OwningPtr<'a, A> {
 | |
|         OwningPtr(self.0, PhantomData)
 | |
|     }
 | |
| 
 | |
|     /// Transforms this [`PtrMut<T>`] into a `&mut T` with the same lifetime
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// - `T` must be the erased pointee type for this [`PtrMut`].
 | |
|     /// - If the type parameter `A` is [`Unaligned`] then this pointer must be sufficiently aligned
 | |
|     ///   for the pointee type `T`.
 | |
|     #[inline]
 | |
|     pub unsafe fn deref_mut<T>(self) -> &'a mut T {
 | |
|         let ptr = self.as_ptr().cast::<T>().debug_ensure_aligned();
 | |
|         // SAFETY: The caller ensures the pointee is of type `T` and the pointer can be dereferenced.
 | |
|         unsafe { &mut *ptr }
 | |
|     }
 | |
| 
 | |
|     /// Gets the underlying pointer, erasing the associated lifetime.
 | |
|     ///
 | |
|     /// If possible, it is strongly encouraged to use [`deref_mut`](Self::deref_mut) over
 | |
|     /// this function, as it retains the lifetime.
 | |
|     #[inline]
 | |
|     #[allow(clippy::wrong_self_convention)]
 | |
|     pub fn as_ptr(&self) -> *mut u8 {
 | |
|         self.0.as_ptr()
 | |
|     }
 | |
| 
 | |
|     /// Gets a [`PtrMut`] from this with a smaller lifetime.
 | |
|     #[inline]
 | |
|     pub fn reborrow(&mut self) -> PtrMut<'_, A> {
 | |
|         // SAFETY: the ptrmut we're borrowing from is assumed to be valid
 | |
|         unsafe { PtrMut::new(self.0) }
 | |
|     }
 | |
| 
 | |
|     /// Gets an immutable reference from this mutable reference
 | |
|     #[inline]
 | |
|     pub fn as_ref(&self) -> Ptr<'_, A> {
 | |
|         // SAFETY: The `PtrMut` type's guarantees about the validity of this pointer are a superset of `Ptr` s guarantees
 | |
|         unsafe { Ptr::new(self.0) }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'a, T: ?Sized> From<&'a mut T> for PtrMut<'a> {
 | |
|     #[inline]
 | |
|     fn from(val: &'a mut T) -> Self {
 | |
|         // SAFETY: The returned pointer has the same lifetime as the passed reference.
 | |
|         // The reference is mutable, and thus will not alias.
 | |
|         unsafe { Self::new(NonNull::from(val).cast()) }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'a> OwningPtr<'a> {
 | |
|     /// Consumes a value and creates an [`OwningPtr`] to it while ensuring a double drop does not happen.
 | |
|     #[inline]
 | |
|     pub fn make<T, F: FnOnce(OwningPtr<'_>) -> R, R>(val: T, f: F) -> R {
 | |
|         let mut temp = ManuallyDrop::new(val);
 | |
|         // SAFETY: The value behind the pointer will not get dropped or observed later,
 | |
|         // so it's safe to promote it to an owning pointer.
 | |
|         f(unsafe { PtrMut::from(&mut *temp).promote() })
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'a, A: IsAligned> OwningPtr<'a, A> {
 | |
|     /// Creates a new instance from a raw pointer.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// - `inner` must point to valid value of whatever the pointee type is.
 | |
|     /// - If the `A` type parameter is [`Aligned`] then `inner` must be sufficiently aligned for the pointee type.
 | |
|     /// - `inner` must have correct provenance to allow read and writes of the pointee type.
 | |
|     /// - The lifetime `'a` must be constrained such that this [`OwningPtr`] will stay valid and nothing
 | |
|     ///   else can read or mutate the pointee while this [`OwningPtr`] is live.
 | |
|     #[inline]
 | |
|     pub unsafe fn new(inner: NonNull<u8>) -> Self {
 | |
|         Self(inner, PhantomData)
 | |
|     }
 | |
| 
 | |
|     /// Consumes the [`OwningPtr`] to obtain ownership of the underlying data of type `T`.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// - `T` must be the erased pointee type for this [`OwningPtr`].
 | |
|     /// - If the type parameter `A` is [`Unaligned`] then this pointer must be sufficiently aligned
 | |
|     ///   for the pointee type `T`.
 | |
|     #[inline]
 | |
|     pub unsafe fn read<T>(self) -> T {
 | |
|         let ptr = self.as_ptr().cast::<T>().debug_ensure_aligned();
 | |
|         // SAFETY: The caller ensure the pointee is of type `T` and uphold safety for `read`.
 | |
|         unsafe { ptr.read() }
 | |
|     }
 | |
| 
 | |
|     /// Consumes the [`OwningPtr`] to drop the underlying data of type `T`.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// - `T` must be the erased pointee type for this [`OwningPtr`].
 | |
|     /// - If the type parameter `A` is [`Unaligned`] then this pointer must be sufficiently aligned
 | |
|     ///   for the pointee type `T`.
 | |
|     #[inline]
 | |
|     pub unsafe fn drop_as<T>(self) {
 | |
|         let ptr = self.as_ptr().cast::<T>().debug_ensure_aligned();
 | |
|         // SAFETY: The caller ensure the pointee is of type `T` and uphold safety for `drop_in_place`.
 | |
|         unsafe {
 | |
|             ptr.drop_in_place();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Gets the underlying pointer, erasing the associated lifetime.
 | |
|     ///
 | |
|     /// If possible, it is strongly encouraged to use the other more type-safe functions
 | |
|     /// over this function.
 | |
|     #[inline]
 | |
|     #[allow(clippy::wrong_self_convention)]
 | |
|     pub fn as_ptr(&self) -> *mut u8 {
 | |
|         self.0.as_ptr()
 | |
|     }
 | |
| 
 | |
|     /// Gets an immutable pointer from this owned pointer.
 | |
|     #[inline]
 | |
|     pub fn as_ref(&self) -> Ptr<'_, A> {
 | |
|         // SAFETY: The `Owning` type's guarantees about the validity of this pointer are a superset of `Ptr` s guarantees
 | |
|         unsafe { Ptr::new(self.0) }
 | |
|     }
 | |
| 
 | |
|     /// Gets a mutable pointer from this owned pointer.
 | |
|     #[inline]
 | |
|     pub fn as_mut(&mut self) -> PtrMut<'_, A> {
 | |
|         // SAFETY: The `Owning` type's guarantees about the validity of this pointer are a superset of `Ptr` s guarantees
 | |
|         unsafe { PtrMut::new(self.0) }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'a> OwningPtr<'a, Unaligned> {
 | |
|     /// Consumes the [`OwningPtr`] to obtain ownership of the underlying data of type `T`.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// - `T` must be the erased pointee type for this [`OwningPtr`].
 | |
|     pub unsafe fn read_unaligned<T>(self) -> T {
 | |
|         let ptr = self.as_ptr().cast::<T>();
 | |
|         // SAFETY: The caller ensure the pointee is of type `T` and uphold safety for `read_unaligned`.
 | |
|         unsafe { ptr.read_unaligned() }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Conceptually equivalent to `&'a [T]` but with length information cut out for performance reasons
 | |
| pub struct ThinSlicePtr<'a, T> {
 | |
|     ptr: NonNull<T>,
 | |
|     #[cfg(debug_assertions)]
 | |
|     len: usize,
 | |
|     _marker: PhantomData<&'a [T]>,
 | |
| }
 | |
| 
 | |
| impl<'a, T> ThinSlicePtr<'a, T> {
 | |
|     #[inline]
 | |
|     /// Indexes the slice without doing bounds checks
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// `index` must be in-bounds.
 | |
|     pub unsafe fn get(self, index: usize) -> &'a T {
 | |
|         #[cfg(debug_assertions)]
 | |
|         debug_assert!(index < self.len);
 | |
| 
 | |
|         let ptr = self.ptr.as_ptr();
 | |
|         // SAFETY: `index` is in-bounds so the resulting pointer is valid to dereference.
 | |
|         unsafe { &*ptr.add(index) }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'a, T> Clone for ThinSlicePtr<'a, T> {
 | |
|     fn clone(&self) -> Self {
 | |
|         *self
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'a, T> Copy for ThinSlicePtr<'a, T> {}
 | |
| 
 | |
| impl<'a, T> From<&'a [T]> for ThinSlicePtr<'a, T> {
 | |
|     #[inline]
 | |
|     fn from(slice: &'a [T]) -> Self {
 | |
|         let ptr = slice.as_ptr().cast_mut();
 | |
|         Self {
 | |
|             // SAFETY: a reference can never be null
 | |
|             ptr: unsafe { NonNull::new_unchecked(ptr.debug_ensure_aligned()) },
 | |
|             #[cfg(debug_assertions)]
 | |
|             len: slice.len(),
 | |
|             _marker: PhantomData,
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Creates a dangling pointer with specified alignment.
 | |
| /// See [`NonNull::dangling`].
 | |
| pub const fn dangling_with_align(align: NonZeroUsize) -> NonNull<u8> {
 | |
|     debug_assert!(align.is_power_of_two(), "Alignment must be power of two.");
 | |
|     // SAFETY: The pointer will not be null, since it was created
 | |
|     // from the address of a `NonZero<usize>`.
 | |
|     unsafe { NonNull::new_unchecked(align.get() as *mut u8) }
 | |
| }
 | |
| 
 | |
| mod private {
 | |
|     use core::cell::UnsafeCell;
 | |
| 
 | |
|     pub trait SealedUnsafeCell {}
 | |
|     impl<'a, T> SealedUnsafeCell for &'a UnsafeCell<T> {}
 | |
| }
 | |
| 
 | |
| /// Extension trait for helper methods on [`UnsafeCell`]
 | |
| pub trait UnsafeCellDeref<'a, T>: private::SealedUnsafeCell {
 | |
|     /// # Safety
 | |
|     /// - The returned value must be unique and not alias any mutable or immutable references to the contents of the [`UnsafeCell`].
 | |
|     /// - At all times, you must avoid data races. If multiple threads have access to the same [`UnsafeCell`], then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference).
 | |
|     unsafe fn deref_mut(self) -> &'a mut T;
 | |
| 
 | |
|     /// # Safety
 | |
|     /// - For the lifetime `'a` of the returned value you must not construct a mutable reference to the contents of the [`UnsafeCell`].
 | |
|     /// - At all times, you must avoid data races. If multiple threads have access to the same [`UnsafeCell`], then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference).
 | |
|     unsafe fn deref(self) -> &'a T;
 | |
| 
 | |
|     /// Returns a copy of the contained value.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// - The [`UnsafeCell`] must not currently have a mutable reference to its content.
 | |
|     /// - At all times, you must avoid data races. If multiple threads have access to the same [`UnsafeCell`], then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference).
 | |
|     unsafe fn read(self) -> T
 | |
|     where
 | |
|         T: Copy;
 | |
| }
 | |
| 
 | |
| impl<'a, T> UnsafeCellDeref<'a, T> for &'a UnsafeCell<T> {
 | |
|     #[inline]
 | |
|     unsafe fn deref_mut(self) -> &'a mut T {
 | |
|         // SAFETY: The caller upholds the alias rules.
 | |
|         unsafe { &mut *self.get() }
 | |
|     }
 | |
|     #[inline]
 | |
|     unsafe fn deref(self) -> &'a T {
 | |
|         // SAFETY: The caller upholds the alias rules.
 | |
|         unsafe { &*self.get() }
 | |
|     }
 | |
| 
 | |
|     #[inline]
 | |
|     unsafe fn read(self) -> T
 | |
|     where
 | |
|         T: Copy,
 | |
|     {
 | |
|         // SAFETY: The caller upholds the alias rules.
 | |
|         unsafe { self.get().read() }
 | |
|     }
 | |
| }
 | |
| 
 | |
| trait DebugEnsureAligned {
 | |
|     fn debug_ensure_aligned(self) -> Self;
 | |
| }
 | |
| 
 | |
| // Disable this for miri runs as it already checks if pointer to reference
 | |
| // casts are properly aligned.
 | |
| #[cfg(all(debug_assertions, not(miri)))]
 | |
| impl<T: Sized> DebugEnsureAligned for *mut T {
 | |
|     #[track_caller]
 | |
|     fn debug_ensure_aligned(self) -> Self {
 | |
|         use core::mem::align_of;
 | |
|         let align = align_of::<T>();
 | |
|         // Implementation shamelessly borrowed from the currently unstable
 | |
|         // ptr.is_aligned_to.
 | |
|         //
 | |
|         // Replace once https://github.com/rust-lang/rust/issues/96284 is stable.
 | |
|         assert_eq!(
 | |
|             self as usize & (align - 1),
 | |
|             0,
 | |
|             "pointer is not aligned. Address {:p} does not have alignment {} for type {}",
 | |
|             self,
 | |
|             align,
 | |
|             core::any::type_name::<T>()
 | |
|         );
 | |
|         self
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[cfg(any(not(debug_assertions), miri))]
 | |
| impl<T: Sized> DebugEnsureAligned for *mut T {
 | |
|     #[inline(always)]
 | |
|     fn debug_ensure_aligned(self) -> Self {
 | |
|         self
 | |
|     }
 | |
| }
 |