1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use std::cell::Cell;
use std::sync::atomic::{AtomicU16, AtomicU32, AtomicU64, AtomicU8, AtomicUsize, Ordering};

/// Trait for refcount
pub trait RefCount {
    /// Type of count
    type Value;

    /// Creates a new RefCount object.
    ///
    /// The object is initialized as "one".
    fn one() -> Self;

    /// Checks whether a value equals to one.
    fn is_one(val: &Self::Value) -> bool;

    /// Gets a current value.
    fn load(&self) -> Self::Value;

    /// Increments its value and returns previous value.
    fn fetch_inc(&self) -> Self::Value;

    /// Decrements its value and returns previous value.
    fn fetch_dec(&self) -> Self::Value;
}

/// Implements RefCount for Cell<$type>.
/// Its implementors are used as single-threaded refcount.
macro_rules! impl_cell_refcount {
    ($type:ty) => {
        impl RefCount for Cell<$type> {
            type Value = $type;

            fn one() -> Self {
                let one = Self::new(1);
                debug_assert!(Self::is_one(&one.load()));
                one
            }

            fn is_one(val: &Self::Value) -> bool {
                *val == 1
            }

            fn load(&self) -> Self::Value {
                self.get()
            }

            fn fetch_inc(&self) -> Self::Value {
                let current = self.load();
                assume!(current != 0);
                match current.checked_add(1) {
                    Some(c) => {
                        self.set(c);
                        current
                    }
                    None => std::process::abort(),
                }
            }

            fn fetch_dec(&self) -> Self::Value {
                let current = self.load();
                assume!(0 < current);
                self.set(current - 1);
                current
            }
        }
    };
}

impl_cell_refcount!(u8);
impl_cell_refcount!(u16);
impl_cell_refcount!(u32);
impl_cell_refcount!(u64);
impl_cell_refcount!(usize);

/// Implements RefCount for atomic $types.
/// Its implementors are used as multi-threaded refcount.
macro_rules! impl_atomic_refcount {
    ($type:ty, $value_type:ty) => {
        impl RefCount for $type {
            type Value = $value_type;

            fn one() -> Self {
                let one = Self::new(1);
                debug_assert!(Self::is_one(&RefCount::load(&one)));
                one
            }

            fn is_one(val: &Self::Value) -> bool {
                *val == 1
            }

            fn load(&self) -> Self::Value {
                self.load(Ordering::Acquire)
            }

            fn fetch_inc(&self) -> Self::Value {
                self.fetch_add(1, Ordering::AcqRel)
            }

            fn fetch_dec(&self) -> Self::Value {
                self.fetch_sub(1, Ordering::AcqRel)
            }
        }
    };
}

impl_atomic_refcount!(AtomicU8, u8);
impl_atomic_refcount!(AtomicU16, u16);
impl_atomic_refcount!(AtomicU32, u32);
impl_atomic_refcount!(AtomicU64, u64);
impl_atomic_refcount!(AtomicUsize, usize);