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