use std::sync::{Arc, Weak};
use std::time::Duration;
use crate::sync::atomic::{AtomicBool, Ordering};
#[must_use = "dropping the handle stops the watch; bind it, or call `.detach()` \
to watch for the rest of the process"]
#[derive(Debug)]
pub struct RemoteWatch {
running: Arc<AtomicBool>,
}
impl RemoteWatch {
pub fn new() -> Self {
Self {
running: Arc::new(AtomicBool::new(true)),
}
}
#[must_use]
pub fn watching(&self) -> Watching {
Watching {
running: Arc::downgrade(&self.running),
}
}
pub fn stop(&self) {
self.running.store(false, Ordering::Release);
}
#[must_use]
pub fn is_stopped(&self) -> bool {
!self.running.load(Ordering::Acquire)
}
pub fn detach(self) {
std::mem::forget(self);
}
}
impl Default for RemoteWatch {
fn default() -> Self {
Self::new()
}
}
impl Drop for RemoteWatch {
fn drop(&mut self) {
self.stop();
}
}
#[derive(Debug, Clone)]
pub struct Watching {
running: Weak<AtomicBool>,
}
impl Watching {
#[must_use]
pub fn keep_going(&self) -> bool {
self.running
.upgrade()
.is_some_and(|running| running.load(Ordering::Acquire))
}
pub fn sleep_for(&self, total: Duration) {
const SLICE: Duration = Duration::from_millis(250);
let mut slept = Duration::ZERO;
while slept < total && self.keep_going() {
std::thread::sleep(SLICE.min(total - slept));
slept += SLICE;
}
}
#[must_use]
pub fn forever() -> Self {
let running = Box::leak(Box::new(Arc::new(AtomicBool::new(true))));
Self {
running: Arc::downgrade(running),
}
}
}