use alloc::boxed::Box;
use core::ptr::NonNull;
pub enum Pointer<T: ?Sized> {
Null,
Ref(NonNull<T>),
Mut(NonNull<T>),
Boxed(NonNull<T>),
}
impl<T: ?Sized> Pointer<T> {
pub fn from_ref(value: &T) -> Self {
Self::Ref(unsafe { NonNull::new_unchecked(<*const _>::cast_mut(value)) })
}
pub fn from_mut(value: &mut T) -> Self {
Self::Mut(unsafe { NonNull::new_unchecked(value) })
}
pub fn from_boxed(value: Box<T>) -> Self {
Self::Boxed(unsafe { NonNull::new_unchecked(Box::leak(value)) })
}
}
impl<T: ?Sized> Copy for Pointer<T> {}
impl<T: ?Sized> Clone for Pointer<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> core::fmt::Debug for Pointer<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Null => write!(f, "Null"),
Self::Ref(ptr) => f.debug_tuple("Ref").field(ptr).finish(),
Self::Mut(ptr) => f.debug_tuple("Mut").field(ptr).finish(),
Self::Boxed(ptr) => f.debug_tuple("Boxed").field(ptr).finish(),
}
}
}
pub struct PointerGuard<T: ?Sized>(Pointer<T>);
impl<T: ?Sized> Drop for PointerGuard<T> {
fn drop(&mut self) {
if let Pointer::Boxed(ptr) = self.0 {
drop(unsafe { Box::from_raw(ptr.as_ptr()) });
}
}
}
impl<T: ?Sized> Pointer<T> {
#[inline]
pub fn into_guard(self) -> PointerGuard<T> {
PointerGuard(self)
}
}