Skip to main content

gcmodule/
ref_count.rs

1use std::cell::Cell;
2
3/// Whether a `GcHeader` exists before the `CcBox<T>`.
4pub(crate) const REF_COUNT_MASK_TRACKED: usize = 0b1;
5
6/// Whether `T` in the `CcBox<T>` has been dropped.
7pub(crate) const REF_COUNT_MASK_DROPPED: usize = 0b10;
8
9/// Number of bits used for metadata.
10pub(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    // Ideally this can be "type Locked<'a> = ..." so there is no need to
21    // duplicate the function to make parking_lot optional. However it's not in
22    // stable Rust yet. See https://github.com/rust-lang/rust/issues/44265.
23    #[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}