1use std::sync::atomic::{fence, AtomicI32, Ordering};
2
3#[doc(hidden)]
4#[repr(transparent)]
5#[derive(Default)]
6pub struct RefCount(pub(crate) AtomicI32);
7
8impl RefCount {
9 /// Creates a new `RefCount` with an initial value of `1`.
10 pub fn new(count: u32) -> Self {
11 Self(AtomicI32::new(count as i32))
12 }
13
14 /// Increments the reference count, returning the new value.
15 pub fn add_ref(&self) -> u32 {
16 (self.0.fetch_add(1, Ordering::Relaxed) + 1) as u32
17 }
18
19 /// Decrements the reference count, returning the new value.
20 ///
21 /// This operation inserts an `Acquire` fence when the reference count reaches zero.
22 /// This prevents reordering before the object is destroyed.
23 pub fn release(&self) -> u32 {
24 let remaining = self.0.fetch_sub(1, Ordering::Release) - 1;
25
26 match remaining.cmp(&0) {
27 std::cmp::Ordering::Equal => fence(Ordering::Acquire),
28 std::cmp::Ordering::Less => panic!("Object has been over-released."),
29 std::cmp::Ordering::Greater => {}
30 }
31
32 remaining as u32
33 }
34}
35