| 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 | |