use std::cell::Cell;
pub(crate) const REF_COUNT_MASK_TRACKED: usize = 0b1;
pub(crate) const REF_COUNT_MASK_DROPPED: usize = 0b10;
pub(crate) const REF_COUNT_SHIFT: i32 = 2;
pub trait RefCount: 'static {
fn is_tracked(&self) -> bool;
fn is_dropped(&self) -> bool;
fn inc_ref(&self) -> usize;
fn dec_ref(&self) -> usize;
fn ref_count(&self) -> usize;
fn set_dropped(&self) -> bool;
#[cfg(not(feature = "sync"))]
#[inline]
fn locked(&self) -> () {
()
}
#[cfg(feature = "sync")]
#[inline]
fn locked(
&self,
) -> Option<parking_lot::lock_api::RwLockReadGuard<'_, parking_lot::RawRwLock, ()>> {
None
}
}
pub struct SingleThreadRefCount(Cell<usize>);
impl SingleThreadRefCount {
pub fn new(tracked: bool) -> Self {
let value = (1 << REF_COUNT_SHIFT) | if tracked { REF_COUNT_MASK_TRACKED } else { 0 };
Self(Cell::new(value))
}
}
impl RefCount for SingleThreadRefCount {
#[inline]
fn is_tracked(&self) -> bool {
Cell::get(&self.0) & REF_COUNT_MASK_TRACKED != 0
}
#[inline]
fn is_dropped(&self) -> bool {
Cell::get(&self.0) & REF_COUNT_MASK_DROPPED != 0
}
#[inline]
fn set_dropped(&self) -> bool {
let value = Cell::get(&self.0);
self.0.set(value | REF_COUNT_MASK_DROPPED);
value & REF_COUNT_MASK_DROPPED != 0
}
#[inline]
fn ref_count(&self) -> usize {
self.0.get() >> REF_COUNT_SHIFT
}
#[inline]
fn inc_ref(&self) -> usize {
let value = Cell::get(&self.0);
self.0.set(value + (1 << REF_COUNT_SHIFT));
value >> REF_COUNT_SHIFT
}
#[inline]
fn dec_ref(&self) -> usize {
let value = Cell::get(&self.0);
self.0.set(value - (1 << REF_COUNT_SHIFT));
value >> REF_COUNT_SHIFT
}
}