use std::borrow::Borrow;
use std::collections::HashMap;
use std::hash::BuildHasher;
use std::hash::Hash;
use std::hash::RandomState;
use std::sync::Arc;
use crate::internal::Mutex;
use crate::once::OnceCell;
#[cfg(test)]
mod tests;
#[derive(Debug)]
pub struct OnceMap<K, V, S = RandomState> {
map: Mutex<HashMap<K, Arc<OnceCell<V>>, S>>,
}
impl<K, V, S> Default for OnceMap<K, V, S>
where
K: Eq + Hash,
V: Clone,
S: BuildHasher + Clone + Default,
{
fn default() -> Self {
Self::with_hasher(S::default())
}
}
impl<K, V> OnceMap<K, V, RandomState>
where
K: Eq + Hash,
V: Clone,
{
pub fn new() -> Self {
Self {
map: Mutex::new(HashMap::new()),
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
map: Mutex::new(HashMap::with_capacity(capacity)),
}
}
}
impl<K, V, S> OnceMap<K, V, S>
where
K: Eq + Hash,
V: Clone,
S: BuildHasher + Clone,
{
pub fn with_hasher(hasher: S) -> Self {
Self {
map: Mutex::new(HashMap::with_hasher(hasher)),
}
}
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
Self {
map: Mutex::new(HashMap::with_capacity_and_hasher(capacity, hasher)),
}
}
pub async fn compute<F>(&self, key: K, func: F) -> V
where
F: AsyncFnOnce() -> V,
{
let cell = {
let mut map = self.map.lock();
map.entry(key)
.or_insert_with(|| Arc::new(OnceCell::new()))
.clone()
};
let res = cell.get_or_init(func).await;
res.clone()
}
pub async fn try_compute<E, F>(&self, key: K, func: F) -> Result<V, E>
where
F: AsyncFnOnce() -> Result<V, E>,
{
let cell = {
let mut map = self.map.lock();
map.entry(key)
.or_insert_with(|| Arc::new(OnceCell::new()))
.clone()
};
let res = cell.get_or_try_init(func).await?;
Ok(res.clone())
}
pub fn get<Q>(&self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let map = self.map.lock();
let cell = map.get(key)?;
cell.get().cloned()
}
pub fn discard<Q>(&self, key: &Q)
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let mut map = self.map.lock();
map.remove(key);
}
pub fn remove<Q>(&self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let cell = self.map.lock().remove(key)?;
cell.get().cloned()
}
}
impl<K, V, S> FromIterator<(K, V)> for OnceMap<K, V, S>
where
K: Eq + Hash + Clone,
V: Clone,
S: Default + BuildHasher + Clone,
{
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
Self {
map: Mutex::new(
iter.into_iter()
.map(|(k, v)| (k, Arc::new(OnceCell::from_value(v))))
.collect(),
),
}
}
}