1use super::Cache;
2use crate::{common::builder_utils, common::concurrent::Weigher};
3
4use std::{
5 collections::hash_map::RandomState,
6 hash::{BuildHasher, Hash},
7 marker::PhantomData,
8 sync::Arc,
9 time::Duration,
10};
11
12#[must_use]
43pub struct CacheBuilder<K, V, C> {
44 max_capacity: Option<u64>,
45 initial_capacity: Option<usize>,
46 weigher: Option<Weigher<K, V>>,
47 time_to_live: Option<Duration>,
48 time_to_idle: Option<Duration>,
49 cache_type: PhantomData<C>,
50}
51
52impl<K, V> Default for CacheBuilder<K, V, Cache<K, V, RandomState>>
53where
54 K: Eq + Hash + Send + Sync + 'static,
55 V: Clone + Send + Sync + 'static,
56{
57 fn default() -> Self {
58 Self {
59 max_capacity: None,
60 initial_capacity: None,
61 weigher: None,
62 time_to_live: None,
63 time_to_idle: None,
64 cache_type: Default::default(),
65 }
66 }
67}
68
69impl<K, V> CacheBuilder<K, V, Cache<K, V, RandomState>>
70where
71 K: Eq + Hash + Send + Sync + 'static,
72 V: Clone + Send + Sync + 'static,
73{
74 pub fn new(max_capacity: u64) -> Self {
77 Self {
78 max_capacity: Some(max_capacity),
79 ..Default::default()
80 }
81 }
82
83 pub fn build(self) -> Cache<K, V, RandomState> {
94 let build_hasher = RandomState::default();
95 builder_utils::ensure_expirations_or_panic(self.time_to_live, self.time_to_idle);
96 Cache::with_everything(
97 self.max_capacity,
98 self.initial_capacity,
99 build_hasher,
100 self.weigher,
101 self.time_to_live,
102 self.time_to_idle,
103 )
104 }
105
106 pub fn build_with_hasher<S>(self, hasher: S) -> Cache<K, V, S>
117 where
118 S: BuildHasher + Clone + Send + Sync + 'static,
119 {
120 builder_utils::ensure_expirations_or_panic(self.time_to_live, self.time_to_idle);
121 Cache::with_everything(
122 self.max_capacity,
123 self.initial_capacity,
124 hasher,
125 self.weigher,
126 self.time_to_live,
127 self.time_to_idle,
128 )
129 }
130}
131
132impl<K, V, C> CacheBuilder<K, V, C> {
133 pub fn max_capacity(self, max_capacity: u64) -> Self {
135 Self {
136 max_capacity: Some(max_capacity),
137 ..self
138 }
139 }
140
141 pub fn initial_capacity(self, number_of_entries: usize) -> Self {
143 Self {
144 initial_capacity: Some(number_of_entries),
145 ..self
146 }
147 }
148
149 pub fn weigher(self, weigher: impl Fn(&K, &V) -> u32 + Send + Sync + 'static) -> Self {
154 Self {
155 weigher: Some(Arc::new(weigher)),
156 ..self
157 }
158 }
159
160 pub fn time_to_live(self, duration: Duration) -> Self {
171 Self {
172 time_to_live: Some(duration),
173 ..self
174 }
175 }
176
177 pub fn time_to_idle(self, duration: Duration) -> Self {
188 Self {
189 time_to_idle: Some(duration),
190 ..self
191 }
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::CacheBuilder;
198
199 use std::time::Duration;
200
201 #[test]
202 fn build_cache() {
203 let cache = CacheBuilder::new(100).build();
205 let policy = cache.policy();
206
207 assert_eq!(policy.max_capacity(), Some(100));
208 assert_eq!(policy.time_to_live(), None);
209 assert_eq!(policy.time_to_idle(), None);
210
211 cache.insert('a', "Alice");
212 assert_eq!(cache.get(&'a'), Some("Alice"));
213
214 let cache = CacheBuilder::new(100)
215 .time_to_live(Duration::from_secs(45 * 60))
216 .time_to_idle(Duration::from_secs(15 * 60))
217 .build();
218 let policy = cache.policy();
219
220 assert_eq!(policy.max_capacity(), Some(100));
221 assert_eq!(policy.time_to_live(), Some(Duration::from_secs(45 * 60)));
222 assert_eq!(policy.time_to_idle(), Some(Duration::from_secs(15 * 60)));
223
224 cache.insert('a', "Alice");
225 assert_eq!(cache.get(&'a'), Some("Alice"));
226 }
227
228 #[test]
229 #[should_panic(expected = "time_to_live is longer than 1000 years")]
230 fn build_cache_too_long_ttl() {
231 let thousand_years_secs: u64 = 1000 * 365 * 24 * 3600;
232 let builder: CacheBuilder<char, String, _> = CacheBuilder::new(100);
233 let duration = Duration::from_secs(thousand_years_secs);
234 builder
235 .time_to_live(duration + Duration::from_secs(1))
236 .build();
237 }
238
239 #[test]
240 #[should_panic(expected = "time_to_idle is longer than 1000 years")]
241 fn build_cache_too_long_tti() {
242 let thousand_years_secs: u64 = 1000 * 365 * 24 * 3600;
243 let builder: CacheBuilder<char, String, _> = CacheBuilder::new(100);
244 let duration = Duration::from_secs(thousand_years_secs);
245 builder
246 .time_to_idle(duration + Duration::from_secs(1))
247 .build();
248 }
249}