mirror of
https://github.com/bevyengine/bevy
synced 2025-01-12 05:09:00 +00:00
211 lines
6.8 KiB
Rust
211 lines
6.8 KiB
Rust
|
use std::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, ptr::NonNull};
|
||
|
|
||
|
/// 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.
|
||
|
///
|
||
|
/// 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)]
|
||
|
pub struct Ptr<'a>(NonNull<u8>, PhantomData<&'a u8>);
|
||
|
|
||
|
/// 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.
|
||
|
///
|
||
|
/// 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.
|
||
|
pub struct PtrMut<'a>(NonNull<u8>, PhantomData<&'a mut u8>);
|
||
|
|
||
|
/// 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.
|
||
|
///
|
||
|
/// 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.
|
||
|
pub struct OwningPtr<'a>(NonNull<u8>, PhantomData<&'a mut u8>);
|
||
|
|
||
|
macro_rules! impl_ptr {
|
||
|
($ptr:ident) => {
|
||
|
impl $ptr<'_> {
|
||
|
/// # Safety
|
||
|
/// the offset cannot make the existing ptr null, or take it out of bounds for its allocation.
|
||
|
#[inline]
|
||
|
pub unsafe fn offset(self, count: isize) -> Self {
|
||
|
Self(
|
||
|
NonNull::new_unchecked(self.0.as_ptr().offset(count)),
|
||
|
PhantomData,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
/// # Safety
|
||
|
/// the offset cannot make the existing ptr null, or take it out of bounds for its allocation.
|
||
|
#[inline]
|
||
|
pub unsafe fn add(self, count: usize) -> Self {
|
||
|
Self(
|
||
|
NonNull::new_unchecked(self.0.as_ptr().add(count)),
|
||
|
PhantomData,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// The lifetime for the returned item must not exceed the lifetime `inner` is valid for
|
||
|
#[inline]
|
||
|
pub unsafe fn new(inner: NonNull<u8>) -> Self {
|
||
|
Self(inner, PhantomData)
|
||
|
}
|
||
|
|
||
|
#[inline]
|
||
|
pub fn inner(&self) -> NonNull<u8> {
|
||
|
self.0
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
impl_ptr!(Ptr);
|
||
|
impl<'a> Ptr<'a> {
|
||
|
/// # 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> {
|
||
|
PtrMut(self.0, PhantomData)
|
||
|
}
|
||
|
|
||
|
/// # Safety
|
||
|
/// Must point to a valid `T`
|
||
|
#[inline]
|
||
|
pub unsafe fn deref<T>(self) -> &'a T {
|
||
|
&*self.0.as_ptr().cast()
|
||
|
}
|
||
|
}
|
||
|
impl_ptr!(PtrMut);
|
||
|
impl<'a> PtrMut<'a> {
|
||
|
/// 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> {
|
||
|
OwningPtr(self.0, PhantomData)
|
||
|
}
|
||
|
|
||
|
/// Transforms this [`PtrMut<T>`] into a `&mut T` with the same lifetime
|
||
|
///
|
||
|
/// # Safety
|
||
|
/// Must point to a valid `T`
|
||
|
#[inline]
|
||
|
pub unsafe fn deref_mut<T>(self) -> &'a mut T {
|
||
|
&mut *self.inner().as_ptr().cast()
|
||
|
}
|
||
|
}
|
||
|
impl_ptr!(OwningPtr);
|
||
|
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 = MaybeUninit::new(val);
|
||
|
let ptr = unsafe { NonNull::new_unchecked(temp.as_mut_ptr().cast::<u8>()) };
|
||
|
f(Self(ptr, PhantomData))
|
||
|
}
|
||
|
|
||
|
//// Consumes the [`OwningPtr`] to obtain ownership of the underlying data of type `T`.
|
||
|
///
|
||
|
/// # Safety
|
||
|
/// Must point to a valid `T`.
|
||
|
#[inline]
|
||
|
pub unsafe fn read<T>(self) -> T {
|
||
|
self.inner().as_ptr().cast::<T>().read()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Conceptually equilavent 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 inbounds.
|
||
|
pub unsafe fn get(self, index: usize) -> &'a T {
|
||
|
#[cfg(debug_assertions)]
|
||
|
debug_assert!(index < self.len);
|
||
|
|
||
|
&*self.ptr.as_ptr().add(index)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl<'a, T> Clone for ThinSlicePtr<'a, T> {
|
||
|
fn clone(&self) -> Self {
|
||
|
Self {
|
||
|
ptr: self.ptr,
|
||
|
#[cfg(debug_assertions)]
|
||
|
len: self.len,
|
||
|
_marker: PhantomData,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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 {
|
||
|
Self {
|
||
|
ptr: unsafe { NonNull::new_unchecked(slice.as_ptr() as *mut T) },
|
||
|
#[cfg(debug_assertions)]
|
||
|
len: slice.len(),
|
||
|
_marker: PhantomData,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub(crate) trait UnsafeCellDeref<'a, T> {
|
||
|
unsafe fn deref_mut(self) -> &'a mut T;
|
||
|
unsafe fn deref(self) -> &'a T;
|
||
|
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 {
|
||
|
&mut *self.get()
|
||
|
}
|
||
|
#[inline]
|
||
|
unsafe fn deref(self) -> &'a T {
|
||
|
&*self.get()
|
||
|
}
|
||
|
|
||
|
#[inline]
|
||
|
unsafe fn read(self) -> T
|
||
|
where
|
||
|
T: Copy,
|
||
|
{
|
||
|
self.get().read()
|
||
|
}
|
||
|
}
|