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#[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)]
157mod 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}