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