use std::cell::UnsafeCell;
use std::ptr::NonNull;
struct Inner<T> {
value: UnsafeCell<T>,
strong: usize,
weak: usize,
}
impl<T> Inner<T> {
unsafe fn try_dealloc(ptr: *mut Self) {
unsafe {
if (*ptr).weak + (*ptr).strong == 0 {
let _ = Box::from_raw(ptr);
}
}
}
}
pub struct BroadRc<T> {
inner: NonNull<Inner<T>>,
}
impl<T> BroadRc<T> {
pub(crate) fn new(value: T) -> Self {
let inner = NonNull::from(Box::leak(Box::new(Inner {
value: UnsafeCell::new(value),
strong: 1,
weak: 0,
})));
Self { inner }
}
pub(crate) fn weak(&self) -> BroadWeak<T> {
unsafe {
let mut inner = &mut (*self.inner.as_ptr());
inner.weak = crate::utils::checked_increment(inner.weak);
BroadWeak { inner: self.inner }
}
}
pub unsafe fn get_mut_unchecked(&self) -> (&mut T, bool) {
let inner = unsafe { &mut (*self.inner.as_ptr()) };
(inner.value.get_mut(), inner.weak != 0)
}
}
pub struct BroadWeak<T> {
inner: NonNull<Inner<T>>,
}
impl<T> BroadWeak<T> {
pub unsafe fn get_mut_unchecked(&self) -> (&mut T, bool) {
let inner = unsafe { &mut (*self.inner.as_ptr()) };
(inner.value.get_mut(), inner.strong != 0)
}
}
impl<T> Drop for BroadRc<T> {
fn drop(&mut self) {
unsafe {
let inner = self.inner.as_ptr();
(*inner).strong = (*inner).strong.wrapping_sub(1);
Inner::try_dealloc(inner);
}
}
}
impl<T> Drop for BroadWeak<T> {
fn drop(&mut self) {
unsafe {
let inner = self.inner.as_ptr();
(*inner).weak = (*inner).weak.wrapping_sub(1);
Inner::try_dealloc(inner);
}
}
}