A better Rust ATProto crate
1

Configure Feed

Select the types of activity you want to include in your feed.

at main 7.3 kB View raw
1use super::{Cache, Weigher}; 2use crate::common::builder_utils; 3 4use std::{ 5 collections::hash_map::RandomState, 6 hash::{BuildHasher, Hash}, 7 marker::PhantomData, 8 time::Duration, 9}; 10 11/// Builds a [`Cache`][cache-struct] with various configuration knobs. 12/// 13/// [cache-struct]: ./struct.Cache.html 14/// 15/// # Examples 16/// 17/// ```rust 18/// use mini_moka_wasm::unsync::Cache; 19/// use std::time::Duration; 20/// 21/// let mut cache = Cache::builder() 22/// // Max 10,000 elements 23/// .max_capacity(10_000) 24/// // Time to live (TTL): 30 minutes 25/// .time_to_live(Duration::from_secs(30 * 60)) 26/// // Time to idle (TTI): 5 minutes 27/// .time_to_idle(Duration::from_secs( 5 * 60)) 28/// // Create the cache. 29/// .build(); 30/// 31/// // This entry will expire after 5 minutes (TTI) if there is no get(). 32/// cache.insert(0, "zero"); 33/// 34/// // This get() will extend the entry life for another 5 minutes. 35/// cache.get(&0); 36/// 37/// // Even though we keep calling get(), the entry will expire 38/// // after 30 minutes (TTL) from the insert(). 39/// ``` 40/// 41#[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, 54{ 55 fn default() -> Self { 56 Self { 57 max_capacity: None, 58 initial_capacity: None, 59 weigher: None, 60 time_to_live: None, 61 time_to_idle: None, 62 cache_type: Default::default(), 63 } 64 } 65} 66 67impl<K, V> CacheBuilder<K, V, Cache<K, V, RandomState>> 68where 69 K: Eq + Hash, 70{ 71 /// Construct a new `CacheBuilder` that will be used to build a `Cache` holding 72 /// up to `max_capacity` entries. 73 pub fn new(max_capacity: u64) -> Self { 74 Self { 75 max_capacity: Some(max_capacity), 76 ..Default::default() 77 } 78 } 79 80 /// Builds a `Cache<K, V>`. 81 /// 82 /// # Panics 83 /// 84 /// Panics if configured with either `time_to_live` or `time_to_idle` higher than 85 /// 1000 years. This is done to protect against overflow when computing key 86 /// expiration. 87 pub fn build(self) -> Cache<K, V, RandomState> { 88 let build_hasher = RandomState::default(); 89 builder_utils::ensure_expirations_or_panic(self.time_to_live, self.time_to_idle); 90 Cache::with_everything( 91 self.max_capacity, 92 self.initial_capacity, 93 build_hasher, 94 self.weigher, 95 self.time_to_live, 96 self.time_to_idle, 97 ) 98 } 99 100 /// Builds a `Cache<K, V, S>`, with the given `hasher`. 101 /// 102 /// # Panics 103 /// 104 /// Panics if configured with either `time_to_live` or `time_to_idle` higher than 105 /// 1000 years. This is done to protect against overflow when computing key 106 /// expiration. 107 pub fn build_with_hasher<S>(self, hasher: S) -> Cache<K, V, S> 108 where 109 S: BuildHasher + Clone, 110 { 111 builder_utils::ensure_expirations_or_panic(self.time_to_live, self.time_to_idle); 112 Cache::with_everything( 113 self.max_capacity, 114 self.initial_capacity, 115 hasher, 116 self.weigher, 117 self.time_to_live, 118 self.time_to_idle, 119 ) 120 } 121} 122 123impl<K, V, C> CacheBuilder<K, V, C> { 124 /// Sets the max capacity of the cache. 125 pub fn max_capacity(self, max_capacity: u64) -> Self { 126 Self { 127 max_capacity: Some(max_capacity), 128 ..self 129 } 130 } 131 132 /// Sets the initial capacity (number of entries) of the cache. 133 pub fn initial_capacity(self, number_of_entries: usize) -> Self { 134 Self { 135 initial_capacity: Some(number_of_entries), 136 ..self 137 } 138 } 139 140 /// Sets the weigher closure of the cache. 141 /// 142 /// The closure should take `&K` and `&V` as the arguments and returns a `u32` 143 /// representing the relative size of the entry. 144 pub fn weigher(self, weigher: impl FnMut(&K, &V) -> u32 + 'static) -> Self { 145 Self { 146 weigher: Some(Box::new(weigher)), 147 ..self 148 } 149 } 150 151 /// Sets the time to live of the cache. 152 /// 153 /// A cached entry will be expired after the specified duration past from 154 /// `insert`. 155 /// 156 /// # Panics 157 /// 158 /// `CacheBuilder::build*` methods will panic if the given `duration` is longer 159 /// than 1000 years. This is done to protect against overflow when computing key 160 /// expiration. 161 pub fn time_to_live(self, duration: Duration) -> Self { 162 Self { 163 time_to_live: Some(duration), 164 ..self 165 } 166 } 167 168 /// Sets the time to idle of the cache. 169 /// 170 /// A cached entry will be expired after the specified duration past from `get` 171 /// or `insert`. 172 /// 173 /// # Panics 174 /// 175 /// `CacheBuilder::build*` methods will panic if the given `duration` is longer 176 /// than 1000 years. This is done to protect against overflow when computing key 177 /// expiration. 178 pub fn time_to_idle(self, duration: Duration) -> Self { 179 Self { 180 time_to_idle: Some(duration), 181 ..self 182 } 183 } 184} 185 186#[cfg(test)] 187mod tests { 188 use super::CacheBuilder; 189 use std::time::Duration; 190 use wasm_bindgen_test::wasm_bindgen_test; 191 192 #[test] 193 #[wasm_bindgen_test] 194 fn build_cache() { 195 // Cache<char, String> 196 let mut cache = CacheBuilder::new(100).build(); 197 let policy = cache.policy(); 198 199 assert_eq!(policy.max_capacity(), Some(100)); 200 assert_eq!(policy.time_to_live(), None); 201 assert_eq!(policy.time_to_idle(), None); 202 203 cache.insert('a', "Alice"); 204 assert_eq!(cache.get(&'a'), Some(&"Alice")); 205 206 let mut cache = CacheBuilder::new(100) 207 .time_to_live(Duration::from_secs(45 * 60)) 208 .time_to_idle(Duration::from_secs(15 * 60)) 209 .build(); 210 let policy = cache.policy(); 211 212 assert_eq!(policy.max_capacity(), Some(100)); 213 assert_eq!(policy.time_to_live(), Some(Duration::from_secs(45 * 60))); 214 assert_eq!(policy.time_to_idle(), Some(Duration::from_secs(15 * 60))); 215 216 cache.insert('a', "Alice"); 217 assert_eq!(cache.get(&'a'), Some(&"Alice")); 218 } 219 220 #[test] 221 #[wasm_bindgen_test] 222 #[should_panic(expected = "time_to_live is longer than 1000 years")] 223 fn build_cache_too_long_ttl() { 224 let thousand_years_secs: u64 = 1000 * 365 * 24 * 3600; 225 let builder: CacheBuilder<char, String, _> = CacheBuilder::new(100); 226 let duration = Duration::from_secs(thousand_years_secs); 227 builder 228 .time_to_live(duration + Duration::from_secs(1)) 229 .build(); 230 } 231 232 #[test] 233 #[wasm_bindgen_test] 234 #[should_panic(expected = "time_to_idle is longer than 1000 years")] 235 fn build_cache_too_long_tti() { 236 let thousand_years_secs: u64 = 1000 * 365 * 24 * 3600; 237 let builder: CacheBuilder<char, String, _> = CacheBuilder::new(100); 238 let duration = Duration::from_secs(thousand_years_secs); 239 builder 240 .time_to_idle(duration + Duration::from_secs(1)) 241 .build(); 242 } 243}