postage/sync/
ref_count.rs1use std::sync::atomic::{AtomicUsize, Ordering};
2
3#[derive(Debug)]
4pub struct RefCount {
5 count: AtomicUsize,
6}
7
8pub enum TryDecrement {
9 Alive(usize),
10 Dead,
11}
12
13impl TryDecrement {
14 #[allow(dead_code)]
15 #[track_caller]
16 pub fn expect_dead(&self, message: &str) {
17 if let Self::Alive(_) = self {
18 panic!("TryDecrement unwrapped on an Alive value: {}", message);
19 }
20 }
21}
22
23impl RefCount {
24 pub fn new(count: usize) -> Self {
25 Self {
26 count: AtomicUsize::new(count),
27 }
28 }
29
30 pub fn is_alive(&self) -> bool {
31 self.count.load(Ordering::Acquire) > 0
32 }
33
34 pub fn increment(&self) {
35 self.count.fetch_add(1, Ordering::AcqRel);
36 }
37
38 pub fn decrement(&self) -> TryDecrement {
39 loop {
40 let state = self.count.load(Ordering::Acquire);
41
42 if state == 0 {
43 return TryDecrement::Dead;
44 }
45
46 if let Ok(_prev) =
47 self.count
48 .compare_exchange(state, state - 1, Ordering::AcqRel, Ordering::Relaxed)
49 {
50 if state == 1 {
51 return TryDecrement::Dead;
52 } else {
53 return TryDecrement::Alive(state - 1);
54 }
55 }
56 }
57 }
58}