#![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::fmt::{self, Formatter, Pointer};
use core::{
cell::UnsafeCell, marker::PhantomData, mem::ManuallyDrop, num::NonZeroUsize, ptr::NonNull,
};
#[derive(Copy, Clone)]
pub struct Aligned;
#[derive(Copy, Clone)]
pub struct Unaligned;
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 {}
}
#[repr(transparent)]
pub struct ConstNonNull<T: ?Sized>(NonNull<T>);
impl<T: ?Sized> ConstNonNull<T> {
pub fn new(ptr: *const T) -> Option<Self> {
NonNull::new(ptr.cast_mut()).map(Self)
}
pub const unsafe fn new_unchecked(ptr: *const T) -> Self {
unsafe { Self(NonNull::new_unchecked(ptr.cast_mut())) }
}
#[inline]
pub unsafe fn as_ref<'a>(&self) -> &'a T {
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))
}
}
#[derive(Copy, Clone, Debug)]
#[repr(transparent)]
pub struct Ptr<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a u8, A)>);
#[derive(Debug)]
#[repr(transparent)]
pub struct PtrMut<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a mut u8, A)>);
#[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> {
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> {
#[inline]
pub unsafe fn byte_offset(self, count: isize) -> Self {
Self(
unsafe { NonNull::new_unchecked(self.as_ptr().offset(count)) },
PhantomData,
)
}
#[inline]
pub unsafe fn byte_add(self, count: usize) -> Self {
Self(
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> {
#[inline]
pub unsafe fn new(inner: NonNull<u8>) -> Self {
Self(inner, PhantomData)
}
#[inline]
pub unsafe fn assert_unique(self) -> PtrMut<'a, A> {
PtrMut(self.0, PhantomData)
}
#[inline]
pub unsafe fn deref<T>(self) -> &'a T {
let ptr = self.as_ptr().cast::<T>().debug_ensure_aligned();
unsafe { &*ptr }
}
#[inline]
#[allow(clippy::wrong_self_convention)]
pub fn as_ptr(self) -> *mut u8 {
self.0.as_ptr()
}
}
impl<'a, T> From<&'a T> for Ptr<'a> {
#[inline]
fn from(val: &'a T) -> Self {
unsafe { Self::new(NonNull::from(val).cast()) }
}
}
impl<'a, A: IsAligned> PtrMut<'a, A> {
#[inline]
pub unsafe fn new(inner: NonNull<u8>) -> Self {
Self(inner, PhantomData)
}
#[inline]
pub unsafe fn promote(self) -> OwningPtr<'a, A> {
OwningPtr(self.0, PhantomData)
}
#[inline]
pub unsafe fn deref_mut<T>(self) -> &'a mut T {
let ptr = self.as_ptr().cast::<T>().debug_ensure_aligned();
unsafe { &mut *ptr }
}
#[inline]
#[allow(clippy::wrong_self_convention)]
pub fn as_ptr(&self) -> *mut u8 {
self.0.as_ptr()
}
#[inline]
pub fn reborrow(&mut self) -> PtrMut<'_, A> {
unsafe { PtrMut::new(self.0) }
}
#[inline]
pub fn as_ref(&self) -> Ptr<'_, A> {
unsafe { Ptr::new(self.0) }
}
}
impl<'a, T> From<&'a mut T> for PtrMut<'a> {
#[inline]
fn from(val: &'a mut T) -> Self {
unsafe { Self::new(NonNull::from(val).cast()) }
}
}
impl<'a> OwningPtr<'a> {
#[inline]
pub fn make<T, F: FnOnce(OwningPtr<'_>) -> R, R>(val: T, f: F) -> R {
let mut temp = ManuallyDrop::new(val);
f(unsafe { PtrMut::from(&mut *temp).promote() })
}
}
impl<'a, A: IsAligned> OwningPtr<'a, A> {
#[inline]
pub unsafe fn new(inner: NonNull<u8>) -> Self {
Self(inner, PhantomData)
}
#[inline]
pub unsafe fn read<T>(self) -> T {
let ptr = self.as_ptr().cast::<T>().debug_ensure_aligned();
unsafe { ptr.read() }
}
#[inline]
pub unsafe fn drop_as<T>(self) {
let ptr = self.as_ptr().cast::<T>().debug_ensure_aligned();
unsafe {
ptr.drop_in_place();
}
}
#[inline]
#[allow(clippy::wrong_self_convention)]
pub fn as_ptr(&self) -> *mut u8 {
self.0.as_ptr()
}
#[inline]
pub fn as_ref(&self) -> Ptr<'_, A> {
unsafe { Ptr::new(self.0) }
}
#[inline]
pub fn as_mut(&mut self) -> PtrMut<'_, A> {
unsafe { PtrMut::new(self.0) }
}
}
impl<'a> OwningPtr<'a, Unaligned> {
pub unsafe fn read_unaligned<T>(self) -> T {
let ptr = self.as_ptr().cast::<T>();
unsafe { ptr.read_unaligned() }
}
}
pub struct ThinSlicePtr<'a, T> {
ptr: NonNull<T>,
#[cfg(debug_assertions)]
len: usize,
_marker: PhantomData<&'a [T]>,
}
impl<'a, T> ThinSlicePtr<'a, T> {
#[inline]
pub unsafe fn get(self, index: usize) -> &'a T {
#[cfg(debug_assertions)]
debug_assert!(index < self.len);
let ptr = self.ptr.as_ptr();
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 {
ptr: unsafe { NonNull::new_unchecked(ptr.debug_ensure_aligned()) },
#[cfg(debug_assertions)]
len: slice.len(),
_marker: PhantomData,
}
}
}
pub fn dangling_with_align(align: NonZeroUsize) -> NonNull<u8> {
debug_assert!(align.is_power_of_two(), "Alignment must be power of two.");
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> {}
}
pub trait UnsafeCellDeref<'a, T>: private::SealedUnsafeCell {
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 {
unsafe { &mut *self.get() }
}
#[inline]
unsafe fn deref(self) -> &'a T {
unsafe { &*self.get() }
}
#[inline]
unsafe fn read(self) -> T
where
T: Copy,
{
unsafe { self.get().read() }
}
}
trait DebugEnsureAligned {
fn debug_ensure_aligned(self) -> Self;
}
#[cfg(all(debug_assertions, not(miri)))]
impl<T: Sized> DebugEnsureAligned for *mut T {
#[track_caller]
fn debug_ensure_aligned(self) -> Self {
let align = core::mem::align_of::<T>();
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
}
}