use lazy_static::lazy_static;
use parking_lot::{Condvar, Mutex, MutexGuard};
use std::sync::atomic::{AtomicBool, Ordering};
lazy_static! {
static ref CURRENT_STEP: Mutex<u64> = Mutex::new(1);
static ref CONDVAR: Condvar = Condvar::new();
static ref ENABLED: AtomicBool = AtomicBool::new(false);
}
#[must_use]
pub enum Step<'a> {
Real {
n: u64,
current_step: MutexGuard<'a, u64>,
},
Dummy,
}
pub fn enable() {
ENABLED.store(true, Ordering::SeqCst)
}
pub fn disable() {
ENABLED.store(false, Ordering::SeqCst)
}
pub fn is_enabled() -> bool {
ENABLED.load(Ordering::SeqCst)
}
pub fn step<'a>(n: u64) -> Step<'a> {
assert_ne!(n, 0, "steps start from 1");
if is_enabled() {
real_step(n)
} else {
Step::Dummy
}
}
fn real_step<'a>(n: u64) -> Step<'a> {
let mut current_step = CURRENT_STEP.lock();
while *current_step != n {
CONDVAR.wait(&mut current_step);
}
Step::Real { n, current_step }
}
impl<'a> Step<'a> {
pub fn then(self, n: u64) -> Step<'a> {
drop(self);
step(n)
}
}
impl<'a> Drop for Step<'a> {
fn drop(&mut self) {
if let Step::Real { current_step, .. } = self {
**current_step += 1;
CONDVAR.notify_all();
}
}
}