#![doc = include_str!("../README.md")] #![no_std] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![expect(unsafe_code, reason = "Raw pointers are inherently unsafe.")] #![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::{self, 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`]'s `*mut T`. #[repr(transparent)] pub struct ConstNonNull(NonNull); impl ConstNonNull { /// Creates a new `ConstNonNull` if `ptr` is non-null. /// /// # Examples /// /// ``` /// use bevy_ptr::ConstNonNull; /// /// let x = 0u32; /// let ptr = ConstNonNull::::new(&x as *const _).expect("ptr is null!"); /// /// if let Some(ptr) = ConstNonNull::::new(core::ptr::null()) { /// unreachable!(); /// } /// ``` pub fn new(ptr: *const T) -> Option { 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::::new_unchecked(core::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 From> for ConstNonNull { fn from(value: NonNull) -> ConstNonNull { ConstNonNull(value) } } impl<'a, T: ?Sized> From<&'a T> for ConstNonNull { fn from(value: &'a T) -> ConstNonNull { ConstNonNull(NonNull::from(value)) } } impl<'a, T: ?Sized> From<&'a mut T> for ConstNonNull { fn from(value: &'a mut T) -> ConstNonNull { 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, 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, 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` 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, 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 { fn from(ptr: $ptr<'a, A>) -> Self { ptr.0 } } impl $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 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) -> 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`] 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(self) -> &'a T { let ptr = self.as_ptr().cast::().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] 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) -> 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`] 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(self) -> &'a mut T { let ptr = self.as_ptr().cast::().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] 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) -> 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) -> 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(self) -> T { let ptr = self.as_ptr().cast::().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(self) { let ptr = self.as_ptr().cast::().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] 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(self) -> T { let ptr = self.as_ptr().cast::(); // 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, #[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 { 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`. // TODO: use https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.with_addr once stabilised unsafe { NonNull::new_unchecked(ptr::null_mut::().wrapping_add(align.get())) } } mod private { use core::cell::UnsafeCell; pub trait SealedUnsafeCell {} impl<'a, T> SealedUnsafeCell for &'a UnsafeCell {} } /// 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 { #[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 DebugEnsureAligned for *mut T { #[track_caller] fn debug_ensure_aligned(self) -> Self { let align = align_of::(); // 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::() ); self } } #[cfg(any(not(debug_assertions), miri))] impl DebugEnsureAligned for *mut T { #[inline(always)] fn debug_ensure_aligned(self) -> Self { self } }