use std::cell::Cell;
use std::marker::PhantomData;
use std::ptr::NonNull;
pub(crate) struct MinRc<T: ?Sized> {
ptr: NonNull<MinRcBox<T>>,
phantomdata: PhantomData<*const T>,
}
pub(super) struct MinRcBox<T: ?Sized> {
pub count: Cell<usize>,
pub inner: T,
}
impl<T> MinRc<T> {
#[inline]
pub fn new(val: T) -> Self {
Self {
ptr: NonNull::new(Box::into_raw(Box::new(MinRcBox {
count: Cell::new(1),
inner: val,
})))
.unwrap(),
phantomdata: PhantomData,
}
}
}
impl<T: ?Sized> MinRc<T> {
#[inline]
pub(super) fn new_with(cb: impl FnOnce() -> Box<MinRcBox<T>>) -> Self {
Self {
ptr: NonNull::new(Box::into_raw(cb())).unwrap(),
phantomdata: PhantomData,
}
}
#[inline]
fn rcbox(&self) -> &MinRcBox<T> {
unsafe { self.ptr.as_ref() }
}
#[inline]
pub fn inner(&self) -> &T {
&self.rcbox().inner
}
}
impl<T: ?Sized> Clone for MinRc<T> {
fn clone(&self) -> Self {
let rcbox = self.rcbox();
rcbox.count.replace(rcbox.count.get().saturating_add(1));
Self {
ptr: self.ptr,
phantomdata: PhantomData,
}
}
}
impl<T: ?Sized> Drop for MinRc<T> {
fn drop(&mut self) {
let rcbox = self.rcbox();
let (count, went_to_zero) = match rcbox.count.get() {
1 => (0, true),
0 => (0, false),
usize::MAX => (usize::MAX, false),
v => (v - 1, false),
};
rcbox.count.replace(count);
if went_to_zero {
unsafe { drop(Box::from_raw(self.ptr.as_mut())) }
}
}
}