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