use std::sync::atomic::{self, AtomicUsize};
use std::ops;
#[derive(PartialEq)]
pub enum State {
Free,
Dead,
Protect(*const u8),
}
pub struct Hazard {
ptr: AtomicUsize,
}
impl Hazard {
pub fn blocked() -> Hazard {
Hazard {
ptr: AtomicUsize::new(0),
}
}
pub fn block(&self) {
self.ptr.store(0, atomic::Ordering::Release);
}
pub fn set(&self, new: State) {
self.ptr.store(match new {
State::Free => 1,
State::Dead => 2,
State::Protect(ptr) => ptr as usize,
}, atomic::Ordering::Release);
}
pub fn get(&self) -> State {
loop {
return match self.ptr.load(atomic::Ordering::Acquire) {
0 => continue,
1 => State::Free,
2 => State::Dead,
ptr => State::Protect(ptr as *const u8)
};
}
}
}
pub fn create() -> (Writer, Reader) {
let ptr: &'static Hazard = unsafe { &*Box::into_raw(Box::new(Hazard::blocked())) };
(Writer {
ptr: ptr,
}, Reader {
ptr: ptr,
})
}
pub struct Reader {
ptr: &'static Hazard,
}
impl Reader {
pub fn get(&self) -> State {
self.ptr.get()
}
pub unsafe fn destroy(self) {
debug_assert!(self.get() == State::Dead, "Prematurely freeing an active hazard.");
Box::from_raw(self.ptr as *const Hazard as *mut Hazard);
}
}
impl Drop for Reader {
fn drop(&mut self) {
panic!("Hazard readers ought to be destroyed manually through the `destroy` method.");
}
}
pub struct Writer {
ptr: &'static Hazard,
}
impl ops::Deref for Writer {
type Target = Hazard;
fn deref(&self) -> &Hazard {
self.ptr
}
}
impl Drop for Writer {
fn drop(&mut self) {
self.set(State::Dead);
}
}