use std::sync::{Arc, Condvar, Mutex};
use std::time::{Duration, Instant};
use anyhow::{bail, Result};
pub trait StopState {
fn clear_pending(&mut self);
fn has_pending_hit(&self) -> bool;
fn alive(&self) -> bool;
fn terminated(&self) -> bool {
false
}
}
pub fn wait_for_stop<S, F>(
state: &Arc<(Mutex<S>, Condvar)>,
action: F,
timeout: Duration,
) -> Result<String>
where
S: StopState,
F: FnOnce() -> Result<()>,
{
{
let (lock, _) = &**state;
lock.lock().unwrap().clear_pending();
}
action()?;
let deadline = Instant::now() + timeout;
let (lock, cvar) = &**state;
let mut guard = lock.lock().unwrap();
while guard.alive() && !guard.has_pending_hit() && !guard.terminated() {
let remaining = deadline.saturating_duration_since(Instant::now());
if remaining.is_zero() {
bail!("timeout waiting for stopped event");
}
let r = cvar.wait_timeout(guard, remaining).unwrap();
guard = r.0;
}
Ok(String::new())
}