atomic_arc/
lib.rs

1use std::sync::atomic::{AtomicPtr, Ordering};
2use std::sync::Arc;
3use std::ptr;
4
5/// A reference-counted, nullable, atomic pointer.
6pub struct AtomicArc<T> {
7    ptr: AtomicPtr<T>,
8}
9
10impl<T> AtomicArc<T> {
11    /// Create a new `AtomicArc`.
12    pub fn new(data: Option<T>) -> AtomicArc<T> {
13        let arc = data.map(|val| Arc::new(val));
14        AtomicArc::from_arc(arc)
15    }
16
17    /// Create a new `AtomicArc` from an `Arc`.
18    pub fn from_arc(arc: Option<Arc<T>>) -> AtomicArc<T> {
19        let ptr = into_raw(arc) as *mut _;
20        let ptr = AtomicPtr::new(ptr);
21        AtomicArc {
22            ptr,
23        }
24    }
25
26    /// Get the value of the pointer as an `Arc`.
27    /// This can be done non-atomically since we have a unique reference to the `AtomicArc`.
28    pub fn get_arc(&mut self) -> Option<Arc<T>> {
29        let ptr = *self.ptr.get_mut();
30        unsafe {
31            let arc = from_raw(ptr);
32            let ret = arc.clone();
33            let _ = into_raw(arc);
34            ret
35        }
36    }
37
38    /// Get a reference to the value stored in this `AtomicArc`.
39    /// This can be done non-atomically since we have a unique reference to the `AtomicArc`.
40    pub fn get(&mut self) -> Option<&T> {
41        unsafe {
42            self.ptr.get_mut().as_ref()
43        }
44    }
45
46    /// Convert this `AtomicArc` into a plain old `Arc`
47    pub fn into_arc(mut self) -> Option<Arc<T>> {
48        let ptr = *self.ptr.get_mut();
49        unsafe {
50            from_raw(ptr)
51        }
52    }
53
54    /// Load the value stored in this `AtomicArc`
55    pub fn load(&self, order: Ordering) -> Option<Arc<T>> {
56        let ptr = self.ptr.load(order);
57        unsafe {
58            let arc = from_raw(ptr);
59            let ret = arc.clone();
60            let _ = into_raw(arc);
61            ret
62        }
63    }
64
65    /// Store a new value.
66    pub fn store(&self, new: Option<Arc<T>>, order: Ordering) {
67        let _drop = self.swap(new, order);
68    }
69
70    /// Atomically swap the value stored in this `AtomicArc` with the new value, returning the old
71    /// value.
72    pub fn swap(&self, new: Option<Arc<T>>, order: Ordering) -> Option<Arc<T>> {
73        let new_ptr = into_raw(new) as *mut _;
74        let old_ptr = self.ptr.swap(new_ptr, order);
75        unsafe {
76            from_raw(old_ptr)
77        }
78    }
79
80    /// Atomically swaps the value stored in this `AtomicArc` if `old` points to the same `Arc` as
81    /// what is currently stored. This does not compare the underlying data, merely that the
82    /// pointers match. Returns the previous value stored in this `AtomicArc`, which will be the
83    /// same as `old` if the swap was successful.
84    pub fn compare_and_swap(
85        &self,
86        old: Option<Arc<T>>,
87        new: Option<Arc<T>>,
88        order: Ordering,
89    ) -> Option<Arc<T>> {
90        let old_ptr = into_raw(old) as *mut _;
91        let new_ptr = into_raw(new) as *mut _;
92        let prev_ptr = self.ptr.compare_and_swap(old_ptr, new_ptr, order);
93        if old_ptr == prev_ptr {
94            unsafe {
95                let _drop = from_raw(old_ptr);
96                from_raw(old_ptr)
97            }
98        } else {
99            unsafe {
100                from_raw(new_ptr)
101            }
102        }
103    }
104}
105
106fn into_raw<T>(a: Option<Arc<T>>) -> *const T {
107    a.map(|a| Arc::into_raw(a)).unwrap_or(ptr::null())
108}
109
110unsafe fn from_raw<T>(ptr: *const T) -> Option<Arc<T>> {
111    if ptr.is_null() {
112        None
113    } else {
114        Some(Arc::from_raw(ptr))
115    }
116}
117