1use std::cell::Cell;
2
3pub(crate) const REF_COUNT_MASK_TRACKED: usize = 0b1;
5
6pub(crate) const REF_COUNT_MASK_DROPPED: usize = 0b10;
8
9pub(crate) const REF_COUNT_SHIFT: i32 = 2;
11
12pub trait RefCount: 'static {
13 fn is_tracked(&self) -> bool;
14 fn is_dropped(&self) -> bool;
15 fn inc_ref(&self) -> usize;
16 fn dec_ref(&self) -> usize;
17 fn ref_count(&self) -> usize;
18 fn set_dropped(&self) -> bool;
19
20 #[cfg(not(feature = "sync"))]
24 #[inline]
25 fn locked(&self) -> () {
26 ()
27 }
28
29 #[cfg(feature = "sync")]
30 #[inline]
31 fn locked(
32 &self,
33 ) -> Option<parking_lot::lock_api::RwLockReadGuard<'_, parking_lot::RawRwLock, ()>> {
34 None
35 }
36}
37
38pub struct SingleThreadRefCount(Cell<usize>);
39
40impl SingleThreadRefCount {
41 pub fn new(tracked: bool) -> Self {
42 let value = (1 << REF_COUNT_SHIFT) | if tracked { REF_COUNT_MASK_TRACKED } else { 0 };
43 Self(Cell::new(value))
44 }
45}
46
47impl RefCount for SingleThreadRefCount {
48 #[inline]
49 fn is_tracked(&self) -> bool {
50 Cell::get(&self.0) & REF_COUNT_MASK_TRACKED != 0
51 }
52
53 #[inline]
54 fn is_dropped(&self) -> bool {
55 Cell::get(&self.0) & REF_COUNT_MASK_DROPPED != 0
56 }
57
58 #[inline]
59 fn set_dropped(&self) -> bool {
60 let value = Cell::get(&self.0);
61 self.0.set(value | REF_COUNT_MASK_DROPPED);
62 value & REF_COUNT_MASK_DROPPED != 0
63 }
64
65 #[inline]
66 fn ref_count(&self) -> usize {
67 self.0.get() >> REF_COUNT_SHIFT
68 }
69
70 #[inline]
71 fn inc_ref(&self) -> usize {
72 let value = Cell::get(&self.0);
73 self.0.set(value + (1 << REF_COUNT_SHIFT));
74 value >> REF_COUNT_SHIFT
75 }
76
77 #[inline]
78 fn dec_ref(&self) -> usize {
79 let value = Cell::get(&self.0);
80 self.0.set(value - (1 << REF_COUNT_SHIFT));
81 value >> REF_COUNT_SHIFT
82 }
83}