Skip to main content

cached/stores/
mod.rs

1use crate::Cached;
2use std::cmp::Eq;
3use std::collections::hash_map::Entry;
4use std::collections::HashMap;
5use std::hash::Hash;
6
7#[cfg(feature = "async")]
8use {super::CachedAsync, async_trait::async_trait, futures::Future};
9
10#[cfg(feature = "disk_store")]
11mod disk;
12#[cfg(feature = "time_stores")]
13mod expiring_sized;
14mod expiring_value_cache;
15#[cfg(feature = "redis_store")]
16mod redis;
17mod sized;
18#[cfg(feature = "time_stores")]
19mod timed;
20#[cfg(feature = "time_stores")]
21mod timed_sized;
22mod unbound;
23
24/// Enum used for defining the status of time-cached values
25#[derive(Debug)]
26pub(super) enum Status {
27    NotFound,
28    Found,
29    Expired,
30}
31
32#[cfg(feature = "disk_store")]
33pub use crate::stores::disk::{DiskCache, DiskCacheBuildError, DiskCacheBuilder, DiskCacheError};
34#[cfg(feature = "redis_store")]
35#[cfg_attr(docsrs, doc(cfg(feature = "redis_store")))]
36pub use crate::stores::redis::{
37    RedisCache, RedisCacheBuildError, RedisCacheBuilder, RedisCacheError,
38};
39#[cfg(feature = "time_stores")]
40#[cfg_attr(docsrs, doc(cfg(feature = "time_stores")))]
41pub use expiring_sized::ExpiringSizedCache;
42pub use expiring_value_cache::{CanExpire, ExpiringValueCache};
43pub use sized::SizedCache;
44#[cfg(feature = "time_stores")]
45#[cfg_attr(docsrs, doc(cfg(feature = "time_stores")))]
46pub use timed::TimedCache;
47#[cfg(feature = "time_stores")]
48#[cfg_attr(docsrs, doc(cfg(feature = "time_stores")))]
49pub use timed_sized::TimedSizedCache;
50pub use unbound::UnboundCache;
51
52#[cfg(all(
53    feature = "async",
54    feature = "redis_store",
55    any(feature = "redis_smol", feature = "redis_tokio")
56))]
57#[cfg_attr(
58    docsrs,
59    doc(cfg(all(
60        feature = "async",
61        feature = "redis_store",
62        any(feature = "redis_smol", feature = "redis_tokio")
63    )))
64)]
65pub use crate::stores::redis::{AsyncRedisCache, AsyncRedisCacheBuilder};
66
67impl<K, V, S> Cached<K, V> for HashMap<K, V, S>
68where
69    K: Hash + Eq,
70    S: std::hash::BuildHasher + Default,
71{
72    fn cache_get<Q>(&mut self, k: &Q) -> Option<&V>
73    where
74        K: std::borrow::Borrow<Q>,
75        Q: std::hash::Hash + Eq + ?Sized,
76    {
77        self.get(k)
78    }
79    fn cache_get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
80    where
81        K: std::borrow::Borrow<Q>,
82        Q: std::hash::Hash + Eq + ?Sized,
83    {
84        self.get_mut(k)
85    }
86    fn cache_set(&mut self, k: K, v: V) -> Option<V> {
87        self.insert(k, v)
88    }
89    fn cache_get_or_set_with<F: FnOnce() -> V>(&mut self, key: K, f: F) -> &mut V {
90        self.entry(key).or_insert_with(f)
91    }
92    fn cache_try_get_or_set_with<F: FnOnce() -> Result<V, E>, E>(
93        &mut self,
94        k: K,
95        f: F,
96    ) -> Result<&mut V, E> {
97        let v = match self.entry(k) {
98            Entry::Occupied(occupied) => occupied.into_mut(),
99            Entry::Vacant(vacant) => vacant.insert(f()?),
100        };
101
102        Ok(v)
103    }
104    fn cache_remove<Q>(&mut self, k: &Q) -> Option<V>
105    where
106        K: std::borrow::Borrow<Q>,
107        Q: std::hash::Hash + Eq + ?Sized,
108    {
109        self.remove(k)
110    }
111    fn cache_clear(&mut self) {
112        self.clear();
113    }
114    fn cache_reset(&mut self) {
115        *self = HashMap::default();
116    }
117    fn cache_size(&self) -> usize {
118        self.len()
119    }
120}
121
122#[cfg(feature = "async")]
123#[async_trait]
124impl<K, V, S> CachedAsync<K, V> for HashMap<K, V, S>
125where
126    K: Hash + Eq + Clone + Send,
127    S: std::hash::BuildHasher + Send,
128{
129    async fn get_or_set_with<F, Fut>(&mut self, k: K, f: F) -> &mut V
130    where
131        V: Send,
132        F: FnOnce() -> Fut + Send,
133        Fut: Future<Output = V> + Send,
134    {
135        match self.entry(k) {
136            Entry::Occupied(o) => o.into_mut(),
137            Entry::Vacant(v) => v.insert(f().await),
138        }
139    }
140
141    async fn try_get_or_set_with<F, Fut, E>(&mut self, k: K, f: F) -> Result<&mut V, E>
142    where
143        V: Send,
144        F: FnOnce() -> Fut + Send,
145        Fut: Future<Output = Result<V, E>> + Send,
146    {
147        let v = match self.entry(k) {
148            Entry::Occupied(o) => o.into_mut(),
149            Entry::Vacant(v) => v.insert(f().await?),
150        };
151
152        Ok(v)
153    }
154}
155
156#[cfg(test)]
157/// Cache store tests
158mod tests {
159    use super::*;
160
161    #[test]
162    fn hashmap() {
163        let mut c = std::collections::HashMap::new();
164        assert!(c.cache_get(&1).is_none());
165        assert_eq!(c.cache_misses(), None);
166
167        assert_eq!(c.cache_set(1, 100), None);
168        assert_eq!(c.cache_get(&1), Some(&100));
169        assert_eq!(c.cache_hits(), None);
170        assert_eq!(c.cache_misses(), None);
171    }
172}