use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
use tokio::sync::Notify;
use crate::identity::TaskId;
#[derive(Default)]
struct PendingInner {
counts: HashMap<TaskId, usize>,
labels: HashMap<TaskId, Arc<str>>,
}
#[derive(Default)]
pub(in crate::core::registry) struct PendingJoins {
inner: Mutex<PendingInner>,
drained: Notify,
}
impl PendingJoins {
pub(super) fn inc_with_label(&self, id: TaskId, label: Arc<str>) {
let mut state = self.inner.lock().unwrap_or_else(|error| error.into_inner());
*state.counts.entry(id).or_insert(0) += 1;
state.labels.insert(id, label);
}
#[cfg(test)]
pub(in crate::core::registry) fn inc(&self, id: TaskId) {
let mut state = self.inner.lock().unwrap_or_else(|error| error.into_inner());
*state.counts.entry(id).or_insert(0) += 1;
}
#[cfg(test)]
pub(in crate::core::registry) fn label(&self, id: TaskId, label: Arc<str>) {
let mut state = self.inner.lock().unwrap_or_else(|error| error.into_inner());
if state.counts.contains_key(&id) {
state.labels.insert(id, label);
}
}
pub(in crate::core::registry) fn dec(&self, id: TaskId) {
let mut state = self.inner.lock().unwrap_or_else(|error| error.into_inner());
if let Some(count) = state.counts.get_mut(&id) {
if *count <= 1 {
state.counts.remove(&id);
state.labels.remove(&id);
} else {
*count -= 1;
}
}
if state.counts.is_empty() {
self.drained.notify_waiters();
}
}
#[cfg(test)]
pub(in crate::core::registry) fn contains(&self, id: TaskId) -> bool {
self.inner
.lock()
.unwrap_or_else(|error| error.into_inner())
.counts
.contains_key(&id)
}
pub(in crate::core::registry) fn is_empty(&self) -> bool {
self.inner
.lock()
.unwrap_or_else(|error| error.into_inner())
.counts
.is_empty()
}
pub(super) fn pending_labels(&self) -> Vec<Arc<str>> {
self.inner
.lock()
.unwrap_or_else(|error| error.into_inner())
.labels
.values()
.cloned()
.collect()
}
pub(in crate::core::registry) async fn wait_drained(&self) {
loop {
let notified = self.drained.notified();
tokio::pin!(notified);
notified.as_mut().enable();
if self.is_empty() {
return;
}
notified.await;
}
}
}