use std::collections::HashSet;
use zksync_concurrency::sync;
use crate::watch::Watch;
#[derive(Clone)]
pub(crate) struct Pool<K, V> {
extra_limit: usize,
extra_count: usize,
allowed: HashSet<K>,
current: im::HashMap<K, V>,
}
impl<K, V> Pool<K, V> {
pub(crate) fn current(&self) -> &im::HashMap<K, V> {
&self.current
}
}
pub(crate) struct PoolWatch<K, V>(Watch<Pool<K, V>>);
impl<K: std::hash::Hash + Eq + Clone, V: Clone> PoolWatch<K, V> {
pub(crate) fn new(allowed: HashSet<K>, extra_limit: usize) -> Self {
Self(Watch::new(Pool {
extra_limit,
extra_count: 0,
allowed,
current: im::HashMap::new(),
}))
}
pub(crate) async fn insert(&self, k: K, v: V) -> anyhow::Result<()> {
self.0
.send_if_ok(|pool| {
if pool.current.contains_key(&k) {
anyhow::bail!("already exists");
}
if !pool.allowed.contains(&k) {
if pool.extra_count >= pool.extra_limit {
anyhow::bail!("limit exceeded");
}
pool.extra_count += 1;
}
pool.current.insert(k, v);
Ok(())
})
.await
}
pub(crate) async fn remove(&self, k: &K) {
self.0.lock().await.send_if_modified(|pool| {
if pool.current.remove(k).is_none() {
return false;
}
if !pool.allowed.contains(k) {
pool.extra_count -= 1;
}
true
});
}
pub(crate) fn current(&self) -> im::HashMap<K, V> {
self.0.subscribe().borrow().current.clone()
}
pub(crate) fn subscribe(&self) -> sync::watch::Receiver<Pool<K, V>> {
self.0.subscribe()
}
}