use std::{mem, ptr};
use std::sync::Arc;
use std::sync::atomic::{AtomicPtr, Ordering};
#[derive(Debug)]
pub struct AtomicArc<T> {
ptr: AtomicPtr<T>,
}
impl<T> AtomicArc<T> {
pub fn empty() -> AtomicArc<T> {
AtomicArc {
ptr: AtomicPtr::new(ptr::null_mut()),
}
}
pub fn set(&self, arc: Arc<T>) -> Result<(), Arc<T>> {
let ptr = Arc::into_raw(arc);
match self.ptr.compare_exchange(ptr::null_mut(), ptr as *mut T,
Ordering::SeqCst, Ordering::Relaxed)
{
Ok(_) => Ok(()),
Err(_) => Err(unsafe { Arc::from_raw(ptr) }),
}
}
pub fn get(&self) -> Option<Arc<T>> {
match self.ptr.load(Ordering::Relaxed) {
ptr if ptr.is_null() => None,
ptr => {
let arc: Arc<T> = unsafe { Arc::from_raw(ptr) };
let c = Arc::clone(&arc);
mem::forget(arc);
Some(c)
},
}
}
}
impl<T> Drop for AtomicArc<T> {
fn drop(&mut self) {
let ptr = self.ptr.load(Ordering::Relaxed);
if !ptr.is_null() {
mem::drop(unsafe { Arc::from_raw(ptr) });
}
}
}