use core::{fmt, marker::PhantomData, ptr, ptr::NonNull};
#[repr(transparent)]
pub struct ThinPtr<T: ?Sized> {
ptr: NonNull<u8>,
marker: PhantomData<*const T>,
}
impl<T: ?Sized> ThinPtr<T> {
#[inline]
pub fn from_ref(value: &T) -> Self {
let addr = (value as *const T).cast::<u8>().expose_provenance();
unsafe { Self::with_exposed_provenance(addr) }
}
#[inline]
pub unsafe fn with_exposed_provenance(addr: usize) -> Self {
let ptr = ptr::with_exposed_provenance_mut::<u8>(addr);
Self {
ptr: unsafe { NonNull::new_unchecked(ptr) },
marker: PhantomData,
}
}
#[inline]
pub fn expose_provenance(self) -> usize {
self.ptr.as_ptr().expose_provenance()
}
#[inline]
pub fn cast<U: Sized>(self) -> NonNull<U> {
self.ptr.cast::<U>()
}
}
impl<T: ?Sized> Clone for ThinPtr<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for ThinPtr<T> {}
impl<T: ?Sized> PartialEq for ThinPtr<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.ptr == other.ptr
}
}
impl<T: ?Sized> Eq for ThinPtr<T> {}
impl<T: ?Sized> fmt::Debug for ThinPtr<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ThinPtr")
.field("ptr", &self.ptr)
.field("marker", &::core::any::type_name::<T>())
.finish()
}
}