use std::sync::{
atomic::{AtomicUsize, Ordering},
Arc,
};
#[derive(Copy, Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord, thiserror::Error)]
#[error("ready notifiers dropped before notifying")]
pub struct WaitError;
#[derive(Debug)]
pub struct Waiter {
rx: tokio::sync::mpsc::Receiver<()>,
notifier: Notifier,
}
impl Waiter {
pub fn new(count: usize) -> Self {
let (tx, rx) = tokio::sync::mpsc::channel(1);
Self {
rx,
notifier: Notifier {
count: Arc::new(AtomicUsize::new(count)),
tx,
},
}
}
pub fn notifier(&self) -> Notifier {
self.notifier.clone()
}
pub async fn wait(mut self) -> Result<(), WaitError> {
drop(self.notifier);
self.rx.recv().await.ok_or(WaitError)
}
}
#[derive(Clone, Debug)]
pub struct Notifier {
count: Arc<AtomicUsize>,
tx: tokio::sync::mpsc::Sender<()>,
}
impl Notifier {
pub fn notify(self) {
if self.count.fetch_sub(1, Ordering::AcqRel) == 1 {
self.tx.try_send(()).ok();
}
}
}