1 | use std::sync::atomic::{fence, AtomicI32, Ordering}; |
2 | |
3 | #[doc (hidden)] |
4 | #[repr (transparent)] |
5 | #[derive (Default)] |
6 | pub struct RefCount(pub(crate) AtomicI32); |
7 | |
8 | impl 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 | |