use std::mem::{self, ManuallyDrop};
use std::ptr;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::cell::UnsafeCell;
#[derive(Debug)]
pub struct AtomicCell<T> {
state: AtomicUsize,
data: ManuallyDrop<UnsafeCell<T>>,
}
const STATE_EMPTY: usize = 0;
const STATE_FULL: usize = 1;
impl<T> AtomicCell<T> {
pub fn empty() -> AtomicCell<T> {
let empty_data = unsafe { mem::uninitialized() };
AtomicCell {
state: AtomicUsize::new(STATE_EMPTY),
data: ManuallyDrop::new(UnsafeCell::new(empty_data)),
}
}
pub unsafe fn write(&self, value: T) {
ptr::write(self.data.get(), value);
self.state.store(STATE_FULL, Ordering::Relaxed);
}
pub unsafe fn read(&self) -> Option<T> {
match self.state.compare_exchange(STATE_FULL, STATE_EMPTY,
Ordering::SeqCst, Ordering::Relaxed)
{
Ok(_) => Some(ptr::read(self.data.get())),
Err(_) => None,
}
}
}
impl<T> Default for AtomicCell<T> {
fn default() -> AtomicCell<T> {
AtomicCell::empty()
}
}
impl<T> Drop for AtomicCell<T> {
fn drop(&mut self) {
if self.state.load(Ordering::Relaxed) == STATE_FULL {
unsafe { ManuallyDrop::drop(&mut self.data); }
}
}
}
unsafe impl<T: Send> Send for AtomicCell<T> {}
unsafe impl<T: Sync> Sync for AtomicCell<T> {}