use futures::stream::Stream;
use std::borrow::Borrow;
use std::collections::hash_map::{self, HashMap};
use std::fmt::Debug;
use std::hash::Hash;
use std::sync::Arc;
use tokio::sync::Mutex;
use super::guard::Guard;
use super::limit::{AsyncLimit, SyncLimit};
use super::lockable_map_impl::LockableMapImpl;
use super::lockable_trait::Lockable;
use super::map_like::MapLike;
use crate::lockable_map_impl::{Entry, EntryValue, LockableMapConfig};
use crate::map_like::GetOrInsertNoneResult;
use crate::utils::primary_arc::PrimaryArc;
impl<K, V> MapLike<K, Entry<V>> for HashMap<K, Entry<V>>
where
K: Eq + PartialEq + Hash + Clone,
{
type ItemIter<'a>
= std::collections::hash_map::Iter<'a, K, Entry<V>>
where
K: 'a,
V: 'a;
fn new() -> Self {
Self::new()
}
fn len(&self) -> usize {
self.iter().len()
}
fn get_or_insert_none(&mut self, key: &K) -> GetOrInsertNoneResult<Entry<V>> {
match self.entry(key.clone()) {
hash_map::Entry::Occupied(entry) => GetOrInsertNoneResult::Existing(entry.into_mut()),
hash_map::Entry::Vacant(entry) => {
let value = PrimaryArc::new(Mutex::new(EntryValue { value: None }));
let new_entry = entry.insert(value);
GetOrInsertNoneResult::Inserted(new_entry)
}
}
}
fn get(&mut self, key: &K) -> Option<&Entry<V>> {
HashMap::get(self, key)
}
fn remove(&mut self, key: &K) -> Option<Entry<V>> {
self.remove(key)
}
fn iter(&self) -> Self::ItemIter<'_> {
HashMap::iter(self)
}
}
#[derive(Clone)]
pub struct LockableHashMapConfig;
impl LockableMapConfig for LockableHashMapConfig {
type WrappedV<V> = V;
type MapImpl<K, V>
= HashMap<K, Entry<V>>
where
K: Eq + PartialEq + Hash + Clone;
fn borrow_value<V>(v: &V) -> &V {
v
}
fn borrow_value_mut<V>(v: &mut V) -> &mut V {
v
}
fn wrap_value<V>(&self, v: V) -> V {
v
}
fn unwrap_value<V>(v: V) -> V {
v
}
fn on_unlock<V>(&self, _v: Option<&mut V>) {
}
}
#[derive(Debug)]
pub struct LockableHashMap<K, V>
where
K: Eq + PartialEq + Hash + Clone,
{
map_impl: LockableMapImpl<K, V, LockableHashMapConfig>,
}
impl<K, V> Lockable<K, V> for LockableHashMap<K, V>
where
K: Eq + PartialEq + Hash + Clone,
{
type Guard<'a>
= Guard<K, V, LockableHashMapConfig, &'a LockableMapImpl<K, V, LockableHashMapConfig>>
where
K: 'a,
V: 'a;
type OwnedGuard = Guard<K, V, LockableHashMapConfig, Arc<LockableHashMap<K, V>>>;
type SyncLimit<'a, OnEvictFn, E>
= SyncLimit<
K,
V,
LockableHashMapConfig,
&'a LockableMapImpl<K, V, LockableHashMapConfig>,
E,
OnEvictFn,
>
where
OnEvictFn: FnMut(Vec<Self::Guard<'a>>) -> Result<(), E>,
K: 'a,
V: 'a;
type SyncLimitOwned<OnEvictFn, E>
= SyncLimit<K, V, LockableHashMapConfig, Arc<LockableHashMap<K, V>>, E, OnEvictFn>
where
OnEvictFn: FnMut(Vec<Self::OwnedGuard>) -> Result<(), E>;
type AsyncLimit<'a, OnEvictFn, E, F>
= AsyncLimit<
K,
V,
LockableHashMapConfig,
&'a LockableMapImpl<K, V, LockableHashMapConfig>,
E,
F,
OnEvictFn,
>
where
F: Future<Output = Result<(), E>>,
OnEvictFn: FnMut(Vec<Self::Guard<'a>>) -> F,
K: 'a,
V: 'a;
type AsyncLimitOwned<OnEvictFn, E, F>
= AsyncLimit<K, V, LockableHashMapConfig, Arc<LockableHashMap<K, V>>, E, F, OnEvictFn>
where
F: Future<Output = Result<(), E>>,
OnEvictFn: FnMut(Vec<Self::OwnedGuard>) -> F;
}
impl<K, V> LockableHashMap<K, V>
where
K: Eq + PartialEq + Hash + Clone,
{
#[inline]
pub fn new() -> Self {
Self {
map_impl: LockableMapImpl::new(LockableHashMapConfig),
}
}
#[inline]
pub fn num_entries_or_locked(&self) -> usize {
self.map_impl.num_entries_or_locked()
}
#[inline]
pub fn blocking_lock<'a, E, OnEvictFn>(
&'a self,
key: K,
limit: <Self as Lockable<K, V>>::SyncLimit<'a, OnEvictFn, E>,
) -> Result<<Self as Lockable<K, V>>::Guard<'a>, E>
where
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::Guard<'a>>) -> Result<(), E>,
{
LockableMapImpl::blocking_lock(&self.map_impl, key, limit)
}
#[inline]
pub fn blocking_lock_owned<E, OnEvictFn>(
self: &Arc<Self>,
key: K,
limit: <Self as Lockable<K, V>>::SyncLimitOwned<OnEvictFn, E>,
) -> Result<<Self as Lockable<K, V>>::OwnedGuard, E>
where
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::OwnedGuard>) -> Result<(), E>,
{
LockableMapImpl::blocking_lock(Arc::clone(self), key, limit)
}
#[inline]
pub fn try_lock<'a, E, OnEvictFn>(
&'a self,
key: K,
limit: <Self as Lockable<K, V>>::SyncLimit<'a, OnEvictFn, E>,
) -> Result<Option<<Self as Lockable<K, V>>::Guard<'a>>, E>
where
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::Guard<'a>>) -> Result<(), E>,
{
LockableMapImpl::try_lock(&self.map_impl, key, limit)
}
#[inline]
pub fn try_lock_owned<E, OnEvictFn>(
self: &Arc<Self>,
key: K,
limit: <Self as Lockable<K, V>>::SyncLimitOwned<OnEvictFn, E>,
) -> Result<Option<<Self as Lockable<K, V>>::OwnedGuard>, E>
where
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::OwnedGuard>) -> Result<(), E>,
{
LockableMapImpl::try_lock(Arc::clone(self), key, limit)
}
#[inline]
pub async fn try_lock_async<'a, E, F, OnEvictFn>(
&'a self,
key: K,
limit: <Self as Lockable<K, V>>::AsyncLimit<'a, OnEvictFn, E, F>,
) -> Result<Option<<Self as Lockable<K, V>>::Guard<'a>>, E>
where
F: Future<Output = Result<(), E>>,
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::Guard<'a>>) -> F,
{
LockableMapImpl::try_lock_async(&self.map_impl, key, limit).await
}
#[inline]
pub async fn try_lock_owned_async<E, F, OnEvictFn>(
self: &Arc<Self>,
key: K,
limit: <Self as Lockable<K, V>>::AsyncLimitOwned<OnEvictFn, E, F>,
) -> Result<Option<<Self as Lockable<K, V>>::OwnedGuard>, E>
where
F: Future<Output = Result<(), E>>,
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::OwnedGuard>) -> F,
{
LockableMapImpl::try_lock_async(Arc::clone(self), key, limit).await
}
#[inline]
pub async fn async_lock<'a, E, F, OnEvictFn>(
&'a self,
key: K,
limit: <Self as Lockable<K, V>>::AsyncLimit<'a, OnEvictFn, E, F>,
) -> Result<<Self as Lockable<K, V>>::Guard<'a>, E>
where
F: Future<Output = Result<(), E>>,
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::Guard<'a>>) -> F,
{
LockableMapImpl::async_lock(&self.map_impl, key, limit).await
}
#[inline]
pub async fn async_lock_owned<E, F, OnEvictFn>(
self: &Arc<Self>,
key: K,
limit: <Self as Lockable<K, V>>::AsyncLimitOwned<OnEvictFn, E, F>,
) -> Result<<Self as Lockable<K, V>>::OwnedGuard, E>
where
F: Future<Output = Result<(), E>>,
OnEvictFn: FnMut(Vec<<Self as Lockable<K, V>>::OwnedGuard>) -> F,
{
LockableMapImpl::async_lock(Arc::clone(self), key, limit).await
}
#[inline]
pub fn into_entries_unordered(self) -> impl Iterator<Item = (K, V)> {
self.map_impl.into_entries_unordered()
}
#[inline]
pub fn keys_with_entries_or_locked(&self) -> Vec<K> {
self.map_impl.keys_with_entries_or_locked()
}
pub async fn lock_all_entries(
&self,
) -> impl Stream<Item = <Self as Lockable<K, V>>::Guard<'_>> {
LockableMapImpl::lock_all_entries(&self.map_impl).await
}
pub async fn lock_all_entries_owned(
self: &Arc<Self>,
) -> impl Stream<Item = <Self as Lockable<K, V>>::OwnedGuard> + use<K, V> {
LockableMapImpl::lock_all_entries(Arc::clone(self)).await
}
}
impl<K, V> Default for LockableHashMap<K, V>
where
K: Eq + PartialEq + Hash + Clone,
{
fn default() -> Self {
Self::new()
}
}
impl<K, V> Borrow<LockableMapImpl<K, V, LockableHashMapConfig>> for Arc<LockableHashMap<K, V>>
where
K: Eq + PartialEq + Hash + Clone,
{
fn borrow(&self) -> &LockableMapImpl<K, V, LockableHashMapConfig> {
&self.map_impl
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::instantiate_lockable_tests;
instantiate_lockable_tests!(LockableHashMap);
#[test]
fn test_default() {
let lockable_map: LockableHashMap<i64, String> = Default::default();
assert_eq!(0, lockable_map.num_entries_or_locked());
}
}