1 use std::sync::atomic::{self, AtomicI32, Ordering};
2 
3 /// A thread-safe reference count for use with COM implementations.
4 #[repr(transparent)]
5 #[derive(Default)]
6 pub struct RefCount {
7     value: AtomicI32,
8 }
9 
10 impl RefCount {
11     /// Creates a new `RefCount` with an initial value of `1`.
new() -> RefCount12     pub fn new() -> RefCount {
13         RefCount {
14             value: AtomicI32::new(1),
15         }
16     }
17 
18     /// Increments the reference count, returning the new value.
add_ref(&self) -> u3219     pub fn add_ref(&self) -> u32 {
20         (self.value.fetch_add(1, Ordering::Relaxed) + 1) as u32
21     }
22 
23     /// Decrements the reference count, returning the new value.
24     ///
25     /// This operation inserts an `Acquire` fence when the reference count reaches zero.
26     /// This prevents reordering before the object is destroyed.
release(&self) -> u3227     pub fn release(&self) -> u32 {
28         let remaining = self.value.fetch_sub(1, Ordering::Release) - 1;
29 
30         if remaining == 0 {
31             atomic::fence(Ordering::Acquire);
32         } else if remaining < 0 {
33             panic!("Object has been over-released.");
34         }
35 
36         remaining as u32
37     }
38 }
39