use std::{
sync::mpsc::{Receiver, RecvTimeoutError, SyncSender, TrySendError, sync_channel},
thread::{sleep, yield_now},
time::{Duration, Instant},
};
#[derive(Debug)]
pub struct Sleeper {
rx: Receiver<()>,
}
impl Sleeper {
pub fn sleep_until(&self, deadline: Instant) {
let mut now = Instant::now();
if deadline <= now {
yield_now();
return;
}
if self.rx.recv_timeout(deadline.duration_since(now)) == Err(RecvTimeoutError::Disconnected) {
now = Instant::now();
if deadline > now {
sleep(deadline.duration_since(now));
}
}
}
pub fn sleep(&self, dur: Duration) {
let now = Instant::now();
let Some(deadline) = now.checked_add(dur) else {
sleep(dur);
return;
};
self.sleep_until(deadline);
}
}
#[derive(Debug, Clone)]
pub struct SleeperHandle {
tx: SyncSender<()>,
}
impl SleeperHandle {
pub fn cancel(&self) -> bool {
self.tx.try_send(()) != Err(TrySendError::Disconnected(()))
}
}
pub fn cancelable_sleep() -> (SleeperHandle, Sleeper) {
let (tx, rx) = sync_channel(0);
(SleeperHandle { tx }, Sleeper { rx })
}
#[cfg(test)]
#[path = "../tests/thread/cancelable.rs"]
mod tests;