use std::fmt::Debug;
use std::future::Future;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::sync::Notify;
#[derive(Clone)]
pub struct Shutdown {
inner: Arc<(AtomicBool, Notify)>,
}
impl Shutdown {
pub fn new() -> Self {
Self {
inner: Arc::new((AtomicBool::new(false), Notify::new())),
}
}
pub fn shutdown(&self) {
self.inner.0.swap(true, Ordering::Relaxed);
self.inner.1.notify_waiters();
}
pub fn is_terminated(&self) -> bool {
self.inner.0.load(Ordering::Relaxed)
}
pub fn wait(&'_ self) -> impl Future<Output = ()> + Send {
let inner = self.inner.clone();
async move {
if !inner.0.load(Ordering::Relaxed) {
let notify = inner.1.notified();
if !inner.0.load(Ordering::Relaxed) {
notify.await;
}
}
}
}
}
impl Default for Shutdown {
fn default() -> Self {
Self::new()
}
}
impl Debug for Shutdown {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Shutdown")
.field("is_terminated", &self.inner.0.load(Ordering::Relaxed))
.finish()
}
}