use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Condvar, Mutex};
pub trait Latch {
fn set(&self);
}
impl<T: Latch> Latch for std::sync::Arc<T> {
fn set(&self) {
Latch::set(self.as_ref());
}
}
pub trait LatchProbe {
fn is_set(&self) -> bool;
}
impl<T: LatchProbe> LatchProbe for std::sync::Arc<T> {
fn is_set(&self) -> bool {
LatchProbe::is_set(self.as_ref())
}
}
pub(crate) trait LatchWaitProbe: LatchProbe {
fn wait(&self);
}
impl<T: LatchWaitProbe> LatchWaitProbe for std::sync::Arc<T> {
fn wait(&self) {
LatchWaitProbe::wait(self.as_ref());
}
}
#[derive(Default)]
pub struct SpinLatch {
b: AtomicBool,
}
impl SpinLatch {
#[inline]
pub fn new() -> SpinLatch {
SpinLatch {
b: AtomicBool::new(false),
}
}
}
impl Latch for SpinLatch {
#[inline]
fn set(&self) {
self.b.store(true, Ordering::SeqCst);
}
}
impl LatchProbe for SpinLatch {
#[inline]
fn is_set(&self) -> bool {
self.b.load(Ordering::SeqCst)
}
}
pub struct LockLatch<T> {
m: Mutex<Option<T>>,
v: Condvar,
}
impl<T> Default for LockLatch<T> {
fn default() -> Self {
LockLatch {
m: Mutex::new(None),
v: Condvar::new(),
}
}
}
impl<T> LockLatch<T> {
#[inline]
pub fn new() -> LockLatch<T> {
Default::default()
}
#[inline]
pub fn set(&self, v: T) {
let mut guard = self.m.lock().unwrap();
*guard = Some(v);
self.v.notify_all();
}
#[inline]
pub fn take(&self) -> T {
assert!(self.is_set());
let mut lock = self.m.lock().unwrap();
::std::mem::replace(&mut *lock, None).unwrap()
}
}
impl Latch for LockLatch<()> {
#[inline]
fn set(&self) {
let mut guard = self.m.lock().unwrap();
*guard = Some(());
self.v.notify_all();
}
}
impl<T> LatchProbe for LockLatch<T> {
#[inline]
fn is_set(&self) -> bool {
self.m.lock().unwrap().is_some()
}
}
impl<T> LatchWaitProbe for LockLatch<T> {
fn wait(&self) {
let mut guard = self.m.lock().unwrap();
while guard.is_none() {
guard = self.v.wait(guard).unwrap();
}
}
}
#[derive(Debug, Default)]
pub struct CountLatch {
counter: AtomicUsize,
}
impl CountLatch {
#[inline]
pub fn new() -> CountLatch {
CountLatch {
counter: AtomicUsize::new(1),
}
}
#[inline]
pub fn increment(&self) {
debug_assert!(!self.is_set());
self.counter.fetch_add(1, Ordering::Relaxed);
}
}
impl Latch for CountLatch {
#[inline]
fn set(&self) {
self.counter.fetch_sub(1, Ordering::SeqCst);
}
}
impl LatchProbe for CountLatch {
#[inline]
fn is_set(&self) -> bool {
self.counter.load(Ordering::SeqCst) == 0
}
}