flexcell 0.1.0-alpha.1

A flexible cell that allows safe circumvention of double borrow issues.
Documentation
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)
    }
}