use std::sync::atomic::{self, AtomicPtr};
use local;
use garbage::Garbage;
use guard::Guard;
pub struct Cell<T> {
inner: AtomicPtr<T>,
}
impl<T> Cell<T> {
pub fn load(&self, ordering: atomic::Ordering) -> Guard<T> {
Guard::new(|| unsafe { &*self.inner.load(ordering) })
}
pub fn store(&self, new: Box<T>, ordering: atomic::Ordering) {
let ptr = self.inner.swap(Box::into_raw(new), ordering);
local::add_garbage(unsafe { Garbage::new_box(ptr) });
}
pub fn swap(&self, new: Box<T>, ordering: atomic::Ordering) -> Guard<T> {
let guard = Guard::new(|| {
unsafe { &*self.inner.swap(Box::into_raw(new), ordering) }
});
local::add_garbage(unsafe { Garbage::new_box(&*guard) });
guard
}
pub fn compare_and_set(&self, old: &T, new: Box<T>, ordering: atomic::Ordering)
-> Result<(), Box<T>> {
let new = Box::into_raw(new);
let ptr = self.inner.compare_and_swap(old as *const T as *mut T, new, ordering);
if ptr as *const T == old {
local::add_garbage(unsafe { Garbage::new_box(old) });
Ok(())
} else {
Err(unsafe { Box::from_raw(new) })
}
}
pub fn compare_and_swap(&self, old: &T, new: Box<T>, ordering: atomic::Ordering)
-> Result<Guard<T>, (Guard<T>, Box<T>)> {
let new = Box::into_raw(new);
let guard = Guard::new(|| {
unsafe { &*self.inner.compare_and_swap(old as *const T as *mut T, new, ordering) }
});
if &*guard as *const T == old {
local::add_garbage(unsafe { Garbage::new_box(old) });
Ok(guard)
} else {
Err((guard, unsafe { Box::from_raw(new) }))
}
}
}