use std::{
    borrow::Cow,
    collections::{hash_map::RandomState, HashMap},
    hash::{BuildHasher, Hash},
    marker::PhantomData,
    num::NonZeroUsize,
};
pub trait CacheFactory: Send + Sync + 'static {
    fn create<K, V>(&self) -> Box<dyn CacheStorage<Key = K, Value = V>>
    where
        K: Send + Sync + Clone + Eq + Hash + 'static,
        V: Send + Sync + Clone + 'static;
}
pub trait CacheStorage: Send + Sync + 'static {
    type Key: Send + Sync + Clone + Eq + Hash + 'static;
    type Value: Send + Sync + Clone + 'static;
    fn get(&mut self, key: &Self::Key) -> Option<&Self::Value>;
    fn insert(&mut self, key: Cow<'_, Self::Key>, val: Cow<'_, Self::Value>);
    fn remove(&mut self, key: &Self::Key);
    fn clear(&mut self);
    fn iter(&self) -> Box<dyn Iterator<Item = (&'_ Self::Key, &'_ Self::Value)> + '_>;
}
pub struct NoCache;
impl CacheFactory for NoCache {
    fn create<K, V>(&self) -> Box<dyn CacheStorage<Key = K, Value = V>>
    where
        K: Send + Sync + Clone + Eq + Hash + 'static,
        V: Send + Sync + Clone + 'static,
    {
        Box::new(NoCacheImpl {
            _mark1: PhantomData,
            _mark2: PhantomData,
        })
    }
}
struct NoCacheImpl<K, V> {
    _mark1: PhantomData<K>,
    _mark2: PhantomData<V>,
}
impl<K, V> CacheStorage for NoCacheImpl<K, V>
where
    K: Send + Sync + Clone + Eq + Hash + 'static,
    V: Send + Sync + Clone + 'static,
{
    type Key = K;
    type Value = V;
    #[inline]
    fn get(&mut self, _key: &K) -> Option<&V> {
        None
    }
    #[inline]
    fn insert(&mut self, _key: Cow<'_, Self::Key>, _val: Cow<'_, Self::Value>) {}
    #[inline]
    fn remove(&mut self, _key: &K) {}
    #[inline]
    fn clear(&mut self) {}
    fn iter(&self) -> Box<dyn Iterator<Item = (&'_ Self::Key, &'_ Self::Value)> + '_> {
        Box::new(std::iter::empty())
    }
}
pub struct HashMapCache<S = RandomState> {
    _mark: PhantomData<S>,
}
impl<S: Send + Sync + BuildHasher + Default + 'static> HashMapCache<S> {
    pub fn new() -> Self {
        Self { _mark: PhantomData }
    }
}
impl Default for HashMapCache<RandomState> {
    fn default() -> Self {
        Self { _mark: PhantomData }
    }
}
impl<S: Send + Sync + BuildHasher + Default + 'static> CacheFactory for HashMapCache<S> {
    fn create<K, V>(&self) -> Box<dyn CacheStorage<Key = K, Value = V>>
    where
        K: Send + Sync + Clone + Eq + Hash + 'static,
        V: Send + Sync + Clone + 'static,
    {
        Box::new(HashMapCacheImpl::<K, V, S>(HashMap::<K, V, S>::default()))
    }
}
struct HashMapCacheImpl<K, V, S>(HashMap<K, V, S>);
impl<K, V, S> CacheStorage for HashMapCacheImpl<K, V, S>
where
    K: Send + Sync + Clone + Eq + Hash + 'static,
    V: Send + Sync + Clone + 'static,
    S: Send + Sync + BuildHasher + 'static,
{
    type Key = K;
    type Value = V;
    #[inline]
    fn get(&mut self, key: &Self::Key) -> Option<&Self::Value> {
        self.0.get(key)
    }
    #[inline]
    fn insert(&mut self, key: Cow<'_, Self::Key>, val: Cow<'_, Self::Value>) {
        self.0.insert(key.into_owned(), val.into_owned());
    }
    #[inline]
    fn remove(&mut self, key: &Self::Key) {
        self.0.remove(key);
    }
    #[inline]
    fn clear(&mut self) {
        self.0.clear();
    }
    fn iter(&self) -> Box<dyn Iterator<Item = (&'_ Self::Key, &'_ Self::Value)> + '_> {
        Box::new(self.0.iter())
    }
}
pub struct LruCache {
    cap: usize,
}
impl LruCache {
    pub fn new(cap: usize) -> Self {
        Self { cap }
    }
}
impl CacheFactory for LruCache {
    fn create<K, V>(&self) -> Box<dyn CacheStorage<Key = K, Value = V>>
    where
        K: Send + Sync + Clone + Eq + Hash + 'static,
        V: Send + Sync + Clone + 'static,
    {
        Box::new(LruCacheImpl(lru::LruCache::new(
            NonZeroUsize::new(self.cap).unwrap(),
        )))
    }
}
struct LruCacheImpl<K, V>(lru::LruCache<K, V>);
impl<K, V> CacheStorage for LruCacheImpl<K, V>
where
    K: Send + Sync + Clone + Eq + Hash + 'static,
    V: Send + Sync + Clone + 'static,
{
    type Key = K;
    type Value = V;
    #[inline]
    fn get(&mut self, key: &Self::Key) -> Option<&Self::Value> {
        self.0.get(key)
    }
    #[inline]
    fn insert(&mut self, key: Cow<'_, Self::Key>, val: Cow<'_, Self::Value>) {
        self.0.put(key.into_owned(), val.into_owned());
    }
    #[inline]
    fn remove(&mut self, key: &Self::Key) {
        self.0.pop(key);
    }
    #[inline]
    fn clear(&mut self) {
        self.0.clear();
    }
    fn iter(&self) -> Box<dyn Iterator<Item = (&'_ Self::Key, &'_ Self::Value)> + '_> {
        Box::new(self.0.iter())
    }
}