pub mod iter;
use std::borrow::Borrow;
use std::collections::hash_map::RandomState;
use std::fmt::{self, Debug, Formatter};
use std::hash::{BuildHasher, Hash};
use std::iter::FromIterator;
use dashmap::mapref::entry::Entry as DashEntry;
use dashmap::mapref::one::Ref as DashRef;
use dashmap::mapref::one::RefMut as DashMut;
use dashmap::DashMap;
use waitcell::WaitCell;
pub struct WaitCache<K, V, S = RandomState> {
items: DashMap<K, Box<WaitCell<V>>, S>,
}
impl<K: Eq + Hash, V> WaitCache<K, V, RandomState> {
#[must_use]
pub fn new() -> Self {
Self::with_capacity(0)
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self::with_capacity_and_hasher(capacity, RandomState::new())
}
}
impl<K: Eq + Hash, V, S: BuildHasher + Clone> WaitCache<K, V, S> {
#[must_use]
pub fn with_hasher(hasher: S) -> Self {
Self::with_capacity_and_hasher(0, hasher)
}
#[must_use]
pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self {
Self { items: DashMap::with_capacity_and_hasher(capacity, hasher) }
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
#[must_use]
pub fn len(&self) -> usize {
self.items.len()
}
#[must_use]
pub fn capacity(&self) -> usize {
self.items.capacity()
}
pub fn shrink_to_fit(&self) {
self.items.shrink_to_fit()
}
#[must_use]
pub fn hasher(&self) -> &S {
self.items.hasher()
}
pub fn clear(&mut self) {
self.items.clear()
}
#[must_use]
pub fn get<'a, 'b, Q: Eq + Hash + ?Sized>(&'a self, key: &'b Q) -> Option<&'a V>
where K: Borrow<Q> {
self.items.get(key).map(|value| unsafe { self.extend_ref(value).get() })
}
pub fn resolve<F: FnOnce() -> V>(&self, key: K, init: F) -> &V {
match self.items.entry(key) {
DashEntry::Occupied(entry) => unsafe {
self.extend_ref(entry.into_ref().downgrade()).get()
},
DashEntry::Vacant(entry) => {
let cell = unsafe { self.extend_mut(entry.insert(Box::new(WaitCell::new()))) };
cell.init(init())
}
}
}
#[must_use]
pub fn iter(&self) -> iter::Iter<'_, K, V, S> {
iter::Iter { iter: self.items.iter(), current: None }
}
#[must_use]
pub fn keys(&self) -> iter::Keys<'_, K, V, S> {
iter::Keys { iter: self.iter() }
}
#[must_use]
pub fn values(&self) -> iter::Values<'_, K, V, S> {
iter::Values { iter: self.items.iter() }
}
#[must_use]
unsafe fn extend_ref<'a, 'b>(
&'a self,
dref: DashRef<'b, K, Box<WaitCell<V>>, S>,
) -> &'a WaitCell<V> {
&*(dref.value().as_ref() as *const WaitCell<V>)
}
#[allow(clippy::mut_from_ref)]
#[must_use]
unsafe fn extend_mut<'a, 'b>(
&'a self,
mut dref: DashMut<'b, K, Box<WaitCell<V>>, S>,
) -> &'a mut WaitCell<V> {
&mut *(dref.value_mut().as_mut() as *mut WaitCell<V>)
}
#[must_use]
pub fn from_raw_iter_with_hasher<T: IntoIterator<Item = (K, Box<WaitCell<V>>)>>(
iter: T,
hasher: S,
) -> Self {
let iter = iter.into_iter();
let capacity = match iter.size_hint() {
(lower, None) => lower,
(_, Some(upper)) => upper,
};
let result = Self::with_capacity_and_hasher(capacity, hasher);
for (key, boxed) in iter {
result.items.insert(key, boxed);
}
result
}
#[must_use]
pub fn from_iter_with_hasher<T: IntoIterator<Item = (K, V)>>(iter: T, hasher: S) -> Self {
Self::from_raw_iter_with_hasher(
iter.into_iter().map(|(key, value)| (key, Box::new(WaitCell::initialized(value)))),
hasher,
)
}
}
impl<K: Debug + Eq + Hash, V: Debug, S: BuildHasher + Clone> Debug for WaitCache<K, V, S> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.items.fmt(f)
}
}
impl<K: Eq + Hash, V, S: BuildHasher + Clone + Default> Default for WaitCache<K, V, S> {
fn default() -> Self {
Self::with_hasher(Default::default())
}
}
impl<K: Eq + Hash, V> FromIterator<(K, V)> for WaitCache<K, V, RandomState> {
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
Self::from_iter_with_hasher(iter, RandomState::new())
}
}
impl<K: Eq + Hash, V, S: BuildHasher + Clone> IntoIterator for WaitCache<K, V, S> {
type IntoIter = iter::Owned<K, V, S>;
type Item = (K, Option<V>);
fn into_iter(self) -> Self::IntoIter {
iter::Owned { iter: self.items.into_iter() }
}
}