cache/mem.rs
1//! In-memory caching utilities.
2
3use std::{
4 any::{Any, TypeId},
5 collections::{HashMap, hash_map::Entry},
6 fmt::Debug,
7 hash::Hash,
8 sync::Arc,
9 thread,
10};
11
12use serde::{Serialize, de::DeserializeOwned};
13
14use crate::{
15 CacheHandle, CacheHandleInner, CacheValueHolder, Cacheable, CacheableWithState, GenerateFn,
16 GenerateResultFn, GenerateResultWithStateFn, GenerateWithStateFn, Namespace, error::ArcResult,
17 run_generator,
18};
19
20#[derive(Debug)]
21struct TypeMapInner<T> {
22 /// Effectively a map from `T -> HashMap<K, V>`.
23 entries: HashMap<T, Box<dyn Any + Send + Sync>>,
24}
25
26impl<T> Default for TypeMapInner<T> {
27 fn default() -> Self {
28 Self {
29 entries: HashMap::new(),
30 }
31 }
32}
33
34impl<T: Hash + PartialEq + Eq> TypeMapInner<T> {
35 fn get_or_insert<K: Hash + Eq + Any + Send + Sync, V: Any + Send + Sync>(
36 &mut self,
37 namespace: T,
38 key: K,
39 f: impl FnOnce() -> V,
40 ) -> &V {
41 let entry = self
42 .entries
43 .entry(namespace)
44 .or_insert_with(|| Box::<HashMap<K, V>>::default());
45
46 entry
47 .downcast_mut::<HashMap<K, V>>()
48 .unwrap()
49 .entry(key)
50 .or_insert_with(f)
51 }
52}
53
54#[derive(Debug)]
55struct TypeCacheInner<T> {
56 /// A map from key type to another map from key to value handle.
57 ///
58 /// Effectively, the type of this map is `TypeId::of::<K>() -> HashMap<Arc<K>, (V1, Arc<OnceCell<Result<V2, E>>)>`.
59 partial_blocking_map: TypeMapInner<T>,
60 /// A map from key type to another map from key to value handle.
61 ///
62 /// Effectively, the type of this map is `TypeId::of::<K>() -> HashMap<Arc<K>, Arc<OnceCell<Result<V, E>>>`.
63 map: TypeMapInner<T>,
64}
65
66impl<T> Default for TypeCacheInner<T> {
67 fn default() -> Self {
68 Self {
69 partial_blocking_map: TypeMapInner::default(),
70 map: TypeMapInner::default(),
71 }
72 }
73}
74
75impl<T: Hash + PartialEq + Eq> TypeCacheInner<T> {
76 fn generate_blocking<K: Hash + Eq + Any + Send + Sync, V: Send + Sync + Any>(
77 &mut self,
78 namespace: T,
79 key: K,
80 generate_fn: impl GenerateFn<K, V>,
81 ) -> &V {
82 let key = Arc::new(key);
83 self.map
84 .get_or_insert(namespace, key.clone(), move || {
85 CacheHandle::new_blocking(move || generate_fn(key.as_ref()))
86 })
87 .get()
88 }
89
90 fn generate_partial_blocking<
91 K: Hash + Eq + Any + Send + Sync,
92 V1: Send + Sync + Any,
93 V2: Send + Sync + Any,
94 S: Send + Sync + Any,
95 >(
96 &mut self,
97 namespace: T,
98 key: K,
99 blocking_generate_fn: impl FnOnce(&K) -> (V1, S),
100 generate_fn: impl GenerateWithStateFn<K, S, V2>,
101 ) -> (&V1, CacheHandle<V2>) {
102 let key = Arc::new(key);
103 let (v1, handle) =
104 self.partial_blocking_map
105 .get_or_insert(namespace, key.clone(), move || {
106 let (v1, s) = blocking_generate_fn(key.as_ref());
107 (v1, CacheHandle::new(move || generate_fn(key.as_ref(), s)))
108 });
109 (v1, handle.clone())
110 }
111
112 fn generate<K: Hash + Eq + Any + Send + Sync, V: Send + Sync + Any>(
113 &mut self,
114 namespace: T,
115 key: K,
116 generate_fn: impl GenerateFn<K, V>,
117 ) -> CacheHandle<V> {
118 let key = Arc::new(key);
119 self.map
120 .get_or_insert(namespace, key.clone(), move || {
121 CacheHandle::new(move || generate_fn(key.as_ref()))
122 })
123 .clone()
124 }
125}
126
127/// An in-memory cache based on hashable types.
128#[derive(Default, Debug)]
129pub struct TypeCache {
130 inner: TypeCacheInner<TypeId>,
131 inner_with_state: TypeCacheInner<(TypeId, TypeId)>,
132}
133
134impl TypeCache {
135 /// Creates a new cache.
136 pub fn new() -> Self {
137 Self::default()
138 }
139
140 /// The blocking equivalent of [`TypeCache::generate`].
141 pub fn generate_blocking<K: Hash + Eq + Any + Send + Sync, V: Send + Sync + Any>(
142 &mut self,
143 key: K,
144 generate_fn: impl GenerateFn<K, V>,
145 ) -> &V {
146 self.inner
147 .generate_blocking(TypeId::of::<K>(), key, generate_fn)
148 }
149
150 /// Blocks on generating a portion `V1` of the cached value as in [`TypeCache::generate_blocking`],
151 /// then generates the remainder `V2` in the background as in [`TypeCache::generate`].
152 ///
153 /// Accesses a separate cache from [`TypeCache::generate_blocking`] and [`TypeCache::generate`].
154 /// That is, a key being accessed with this method will not affect the set of available
155 /// key-value pairs for the other two methods.
156 pub fn generate_partial_blocking<
157 K: Hash + Eq + Any + Send + Sync,
158 V1: Send + Sync + Any,
159 V2: Send + Sync + Any,
160 S: Send + Sync + Any,
161 >(
162 &mut self,
163 key: K,
164 blocking_generate_fn: impl FnOnce(&K) -> (V1, S),
165 generate_fn: impl GenerateWithStateFn<K, S, V2>,
166 ) -> (&V1, CacheHandle<V2>) {
167 self.inner.generate_partial_blocking(
168 TypeId::of::<K>(),
169 key,
170 blocking_generate_fn,
171 generate_fn,
172 )
173 }
174
175 /// Ensures that a value corresponding to `key` is generated, using `generate_fn`
176 /// to generate it if it has not already been generated.
177 ///
178 /// A more general counterpart to [`TypeCache::get`].
179 ///
180 /// Returns a handle to the value. If the value is not yet generated, it is generated
181 /// in the background.
182 ///
183 /// # Panics
184 ///
185 /// Panics if a different type `V` or `E` is already associated with type `K`.
186 ///
187 /// # Examples
188 ///
189 /// ```
190 /// use std::sync::{Arc, Mutex};
191 /// use cache::{mem::TypeCache, error::Error, CacheableWithState};
192 ///
193 /// let mut cache = TypeCache::new();
194 ///
195 /// fn generate_fn(tuple: &(u64, u64)) -> u64 {
196 /// tuple.0 + tuple.1
197 /// }
198 ///
199 /// let handle = cache.generate((5, 6), generate_fn);
200 /// assert_eq!(*handle.get(), 11);
201 ///
202 /// // Does not call `generate_fn` again as the result has been cached.
203 /// let handle = cache.generate((5, 6), generate_fn);
204 /// assert_eq!(*handle.get(), 11);
205 /// ```
206 pub fn generate<K: Hash + Eq + Any + Send + Sync, V: Send + Sync + Any>(
207 &mut self,
208 key: K,
209 generate_fn: impl GenerateFn<K, V>,
210 ) -> CacheHandle<V> {
211 self.inner.generate(TypeId::of::<K>(), key, generate_fn)
212 }
213
214 /// The blocking equivalent of [`TypeCache::generate_with_state`].
215 pub fn generate_with_state_blocking<
216 K: Hash + Eq + Any + Send + Sync,
217 V: Send + Sync + Any,
218 S: Send + Sync + Any,
219 >(
220 &mut self,
221 key: K,
222 state: S,
223 generate_fn: impl GenerateWithStateFn<K, S, V>,
224 ) -> &V {
225 self.inner_with_state.generate_blocking(
226 (TypeId::of::<K>(), TypeId::of::<S>()),
227 key,
228 move |key| generate_fn(key, state),
229 )
230 }
231
232 /// Ensures that a value corresponding to `key` is generated, using `generate_fn`
233 /// to generate it if it has not already been generated.
234 ///
235 /// A more general counterpart to [`TypeCache::get_with_state`].
236 ///
237 /// Returns a handle to the value. If the value is not yet generated, it is generated
238 /// in the background.
239 ///
240 /// # Panics
241 ///
242 /// Panics if a different type `V` or `E` is already associated with type `K`.
243 ///
244 /// # Examples
245 ///
246 /// ```
247 /// use std::sync::{Arc, Mutex};
248 /// use cache::{mem::TypeCache, error::Error, CacheableWithState};
249 ///
250 /// #[derive(Clone)]
251 /// pub struct Log(Arc<Mutex<Vec<(u64, u64)>>>);
252 ///
253 /// let mut cache = TypeCache::new();
254 /// let log = Log(Arc::new(Mutex::new(Vec::new())));
255 ///
256 /// fn generate_fn(tuple: &(u64, u64), state: Log) -> u64 {
257 /// println!("Logging parameters...");
258 /// state.0.lock().unwrap().push(*tuple);
259 /// tuple.0 + tuple.1
260 /// }
261 ///
262 /// let handle = cache.generate_with_state((5, 6), log.clone(), generate_fn);
263 /// assert_eq!(*handle.get(), 11);
264 ///
265 /// // Does not call `generate_fn` again as the result has been cached.
266 /// let handle = cache.generate_with_state((5, 6), log.clone(), generate_fn);
267 /// assert_eq!(*handle.get(), 11);
268 ///
269 /// assert_eq!(log.0.lock().unwrap().clone(), vec![(5, 6)]);
270 /// ```
271 pub fn generate_with_state<
272 K: Hash + Eq + Any + Send + Sync,
273 V: Send + Sync + Any,
274 S: Send + Sync + Any,
275 >(
276 &mut self,
277 key: K,
278 state: S,
279 generate_fn: impl GenerateWithStateFn<K, S, V>,
280 ) -> CacheHandle<V> {
281 self.inner_with_state
282 .generate((TypeId::of::<K>(), TypeId::of::<S>()), key, move |key| {
283 generate_fn(key, state)
284 })
285 }
286
287 /// The blocking equivalent of [`TypeCache::get`].
288 pub fn get_blocking<K: Cacheable>(
289 &mut self,
290 key: K,
291 ) -> &std::result::Result<K::Output, K::Error> {
292 self.generate_blocking(key, |key| key.generate())
293 }
294
295 /// Gets a handle to a cacheable object from the cache, generating the object in the background
296 /// if needed.
297 ///
298 /// # Examples
299 ///
300 /// ```
301 /// use cache::{mem::TypeCache, error::Error, Cacheable};
302 /// use serde::{Deserialize, Serialize};
303 ///
304 /// #[derive(Deserialize, Serialize, Hash, Eq, PartialEq)]
305 /// pub struct Params {
306 /// param1: u64,
307 /// param2: String,
308 /// };
309 ///
310 /// impl Cacheable for Params {
311 /// type Output = u64;
312 /// type Error = anyhow::Error;
313 ///
314 /// fn generate(&self) -> anyhow::Result<u64> {
315 /// if self.param1 == 5 {
316 /// anyhow::bail!("invalid param");
317 /// } else if &self.param2 == "panic" {
318 /// panic!("unrecoverable param");
319 /// }
320 /// Ok(2 * self.param1)
321 /// }
322 /// }
323 ///
324 /// let mut cache = TypeCache::new();
325 ///
326 /// let handle = cache.get(Params { param1: 50, param2: "cache".to_string() });
327 /// assert_eq!(*handle.unwrap_inner(), 100);
328 ///
329 /// let handle = cache.get(Params { param1: 5, param2: "cache".to_string() });
330 /// assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid param");
331 ///
332 /// let handle = cache.get(Params { param1: 50, param2: "panic".to_string() });
333 /// assert!(matches!(handle.get_err().as_ref(), Error::Panic));
334 /// ```
335 pub fn get<K: Cacheable>(
336 &mut self,
337 key: K,
338 ) -> CacheHandle<std::result::Result<K::Output, K::Error>> {
339 self.generate(key, |key| key.generate())
340 }
341
342 /// The blocking equivalent of [`TypeCache::get_with_state`].
343 pub fn get_with_state_blocking<S: Send + Sync + Any, K: CacheableWithState<S>>(
344 &mut self,
345 key: K,
346 state: S,
347 ) -> &std::result::Result<K::Output, K::Error> {
348 self.generate_with_state_blocking(key, state, |key, state| key.generate_with_state(state))
349 }
350
351 /// Gets a handle to a cacheable object from the cache, generating the object in the background
352 /// if needed.
353 ///
354 /// **Note:** The state is not used to determine whether the object should be regenerated. As
355 /// such, it should not impact the output of this function but rather should only be used to
356 /// store collateral or reuse computation from other function calls.
357 ///
358 /// However, the entries generated with different state types are not interchangeable. That is,
359 /// getting the same key with different states will regenerate the key several times, once for
360 /// each state type `S`.
361 ///
362 /// # Examples
363 ///
364 /// ```
365 /// use std::sync::{Arc, Mutex};
366 /// use cache::{mem::TypeCache, error::Error, CacheableWithState};
367 /// use serde::{Deserialize, Serialize};
368 ///
369 /// #[derive(Debug, Deserialize, Serialize, Clone, Hash, Eq, PartialEq)]
370 /// pub struct Params(u64);
371 ///
372 /// #[derive(Clone)]
373 /// pub struct Log(Arc<Mutex<Vec<Params>>>);
374 ///
375 /// impl CacheableWithState<Log> for Params {
376 /// type Output = u64;
377 /// type Error = anyhow::Error;
378 ///
379 /// fn generate_with_state(&self, state: Log) -> anyhow::Result<u64> {
380 /// println!("Logging parameters...");
381 /// state.0.lock().unwrap().push(self.clone());
382 ///
383 /// if self.0 == 5 {
384 /// anyhow::bail!("invalid param");
385 /// } else if self.0 == 8 {
386 /// panic!("unrecoverable param");
387 /// }
388 /// Ok(2 * self.0)
389 /// }
390 /// }
391 ///
392 /// let mut cache = TypeCache::new();
393 /// let log = Log(Arc::new(Mutex::new(Vec::new())));
394 ///
395 /// let handle = cache.get_with_state(Params(0), log.clone());
396 /// assert_eq!(*handle.unwrap_inner(), 0);
397 ///
398 /// let handle = cache.get_with_state(Params(5), log.clone());
399 /// assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid param");
400 ///
401 /// let handle = cache.get_with_state(Params(8), log.clone());
402 /// assert!(matches!(handle.get_err().as_ref(), Error::Panic));
403 ///
404 /// assert_eq!(log.0.lock().unwrap().clone(), vec![Params(0), Params(5), Params(8)]);
405 /// ```
406 pub fn get_with_state<S: Send + Sync + Any, K: CacheableWithState<S>>(
407 &mut self,
408 key: K,
409 state: S,
410 ) -> CacheHandle<std::result::Result<K::Output, K::Error>> {
411 self.generate_with_state(key, state, |key, state| key.generate_with_state(state))
412 }
413}
414
415/// Maps from a key to a handle on a value that may be set to [`None`] if the generator returns an
416/// uncacheable result. In this case, the result must be regenerated each time.
417type NamespaceEntryMap = HashMap<Vec<u8>, CacheHandleInner<Option<Vec<u8>>>>;
418
419/// Serializes the provided value to bytes, returning [`None`] if the value should not be cached.
420trait SerializeValueFn<V>: FnOnce(&V) -> Option<Vec<u8>> + Send + Any {}
421impl<V, T: FnOnce(&V) -> Option<Vec<u8>> + Send + Any> SerializeValueFn<V> for T {}
422
423/// Deserializes desired value from bytes stored in the cache. If `V` is a result, would need to
424/// wrap the bytes from the cache with an `Ok` since `Err` results are not stored in the cache.
425trait DeserializeValueFn<V>: FnOnce(&[u8]) -> ArcResult<V> + Send + Any {}
426impl<V, T: FnOnce(&[u8]) -> ArcResult<V> + Send + Any> DeserializeValueFn<V> for T {}
427
428/// An in-memory cache based on namespace strings and types that implement [`Serialize`] and
429/// [`Deserialize`](serde::Deserialize).
430///
431/// Unlike a [`TypeCache`], a [`NamespaceCache`] works by serializing and deserializing keys and
432/// values. As such, an entry can be accessed with several generic types as long as all of the
433/// types serialize/deserialize to/from the same bytes.
434#[derive(Default, Debug, Clone)]
435pub struct NamespaceCache {
436 /// A map from namespace to another map from key to value handle.
437 entries: HashMap<Namespace, NamespaceEntryMap>,
438}
439
440impl NamespaceCache {
441 /// Creates a new cache.
442 pub fn new() -> Self {
443 Self::default()
444 }
445
446 /// Ensures that a value corresponding to `key` is generated, using `generate_fn`
447 /// to generate it if it has not already been generated.
448 ///
449 /// A more general counterpart to [`NamespaceCache::get`].
450 ///
451 /// Returns a handle to the value. If the value is not yet generated, it is generated
452 /// in the background.
453 ///
454 /// # Panics
455 ///
456 /// Panics if a different type `V` or `E` is already associated with type `K`.
457 ///
458 /// # Examples
459 ///
460 /// ```
461 /// use cache::{mem::NamespaceCache, error::Error, CacheableWithState};
462 ///
463 /// let mut cache = NamespaceCache::new();
464 ///
465 /// fn generate_fn(tuple: &(u64, u64)) -> u64 {
466 /// tuple.0 + tuple.1
467 /// }
468 ///
469 /// fn generate_fn2(tuple: &(u64, u64)) -> u64 {
470 /// tuple.0 * tuple.1
471 /// }
472 ///
473 /// let handle = cache.generate("example.namespace", (5, 6), generate_fn);
474 /// assert_eq!(*handle.get(), 11);
475 ///
476 /// // Does not call `generate_fn` again as the result has been cached.
477 /// let handle = cache.generate("example.namespace", (5, 6), generate_fn);
478 /// assert_eq!(*handle.get(), 11);
479 ///
480 /// // Calls the new `generate_fn2` as the namespace is different,
481 /// // even though the key is the same.
482 /// let handle = cache.generate("example.namespace2", (5, 6), generate_fn2);
483 /// assert_eq!(*handle.get(), 30);
484 /// ```
485 pub fn generate<
486 K: Serialize + Any + Send + Sync,
487 V: Serialize + DeserializeOwned + Send + Sync + Any,
488 >(
489 &mut self,
490 namespace: impl Into<Namespace>,
491 key: K,
492 generate_fn: impl GenerateFn<K, V>,
493 ) -> CacheHandle<V> {
494 CacheHandle::from_inner(Arc::new(self.generate_inner(namespace, key, generate_fn)))
495 }
496
497 /// Ensures that a value corresponding to `key` is generated, using `generate_fn`
498 /// to generate it if it has not already been generated.
499 ///
500 /// A more general counterpart to [`NamespaceCache::get_with_state`].
501 ///
502 /// Returns a handle to the value. If the value is not yet generated, it is generated
503 /// in the background.
504 ///
505 /// # Panics
506 ///
507 /// Panics if a different type `V` or `E` is already associated with type `K`.
508 ///
509 /// # Examples
510 ///
511 /// ```
512 /// use std::sync::{Arc, Mutex};
513 /// use cache::{mem::NamespaceCache, error::Error, CacheableWithState};
514 ///
515 /// #[derive(Clone)]
516 /// pub struct Log(Arc<Mutex<Vec<(u64, u64)>>>);
517 ///
518 /// let mut cache = NamespaceCache::new();
519 /// let log = Log(Arc::new(Mutex::new(Vec::new())));
520 ///
521 /// fn generate_fn(tuple: &(u64, u64), state: Log) -> u64 {
522 /// println!("Logging parameters...");
523 /// state.0.lock().unwrap().push(*tuple);
524 /// tuple.0 + tuple.1
525 /// }
526 ///
527 /// let handle = cache.generate_with_state("example.namespace", (5, 6), log.clone(), generate_fn);
528 /// assert_eq!(*handle.get(), 11);
529 ///
530 /// // Does not call `generate_fn` again as the result has been cached.
531 /// let handle = cache.generate_with_state("example.namespace", (5, 6), log.clone(), generate_fn);
532 /// assert_eq!(*handle.get(), 11);
533 ///
534 /// assert_eq!(log.0.lock().unwrap().clone(), vec![(5, 6)]);
535 /// ```
536 pub fn generate_with_state<
537 K: Serialize + Any + Send + Sync,
538 V: Serialize + DeserializeOwned + Send + Sync + Any,
539 S: Send + Sync + Any,
540 >(
541 &mut self,
542 namespace: impl Into<Namespace>,
543 key: K,
544 state: S,
545 generate_fn: impl GenerateWithStateFn<K, S, V>,
546 ) -> CacheHandle<V> {
547 let namespace = namespace.into();
548 self.generate(namespace, key, |key| generate_fn(key, state))
549 }
550
551 /// Ensures that a result corresponding to `key` is generated, using `generate_fn`
552 /// to generate it if it has not already been generated.
553 ///
554 /// Does not cache on failure as errors are not constrained to be serializable/deserializable.
555 /// As such, failures should happen quickly, or should be serializable and stored as part of
556 /// cached value using [`NamespaceCache::generate`].
557 ///
558 /// Returns a handle to the value. If the value is not yet generated, it is generated
559 ///
560 /// # Examples
561 ///
562 /// ```
563 /// use cache::{mem::NamespaceCache, error::Error, Cacheable};
564 ///
565 /// let mut cache = NamespaceCache::new();
566 ///
567 /// fn generate_fn(tuple: &(u64, u64)) -> anyhow::Result<u64> {
568 /// if *tuple == (5, 5) {
569 /// Err(anyhow::anyhow!("invalid tuple"))
570 /// } else {
571 /// Ok(tuple.0 + tuple.1)
572 /// }
573 /// }
574 ///
575 /// let handle = cache.generate_result("example.namespace", (5, 5), generate_fn);
576 /// assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid tuple");
577 ///
578 /// // Calls `generate_fn` again as the error was not cached.
579 /// let handle = cache.generate_result("example.namespace", (5, 5), generate_fn);
580 /// assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid tuple");
581 /// ```
582 pub fn generate_result<
583 K: Serialize + Any + Send + Sync,
584 V: Serialize + DeserializeOwned + Send + Sync + Any,
585 E: Send + Sync + Any,
586 >(
587 &mut self,
588 namespace: impl Into<Namespace>,
589 key: K,
590 generate_fn: impl GenerateResultFn<K, V, E>,
591 ) -> CacheHandle<std::result::Result<V, E>> {
592 CacheHandle::from_inner(Arc::new(self.generate_result_inner(
593 namespace,
594 key,
595 generate_fn,
596 )))
597 }
598
599 /// Ensures that a value corresponding to `key` is generated, using `generate_fn`
600 /// to generate it if it has not already been generated.
601 ///
602 /// Does not cache on failure as errors are not constrained to be serializable/deserializable.
603 /// As such, failures should happen quickly, or should be serializable and stored as part of
604 /// cached value using [`NamespaceCache::generate_with_state`].
605 ///
606 /// Returns a handle to the value. If the value is not yet generated, it is generated
607 /// in the background.
608 ///
609 /// # Examples
610 ///
611 /// ```
612 /// use std::sync::{Arc, Mutex};
613 /// use cache::{mem::NamespaceCache, error::Error, Cacheable};
614 ///
615 /// #[derive(Clone)]
616 /// pub struct Log(Arc<Mutex<Vec<(u64, u64)>>>);
617 ///
618 /// let mut cache = NamespaceCache::new();
619 /// let log = Log(Arc::new(Mutex::new(Vec::new())));
620 ///
621 /// fn generate_fn(tuple: &(u64, u64), state: Log) -> anyhow::Result<u64> {
622 /// println!("Logging parameters...");
623 /// state.0.lock().unwrap().push(*tuple);
624 ///
625 /// if *tuple == (5, 5) {
626 /// Err(anyhow::anyhow!("invalid tuple"))
627 /// } else {
628 /// Ok(tuple.0 + tuple.1)
629 /// }
630 /// }
631 ///
632 /// let handle = cache.generate_result_with_state(
633 /// "example.namespace", (5, 5), log.clone(), generate_fn
634 /// );
635 /// assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid tuple");
636 ///
637 /// // Calls `generate_fn` again as the error was not cached.
638 /// let handle = cache.generate_result_with_state(
639 /// "example.namespace", (5, 5), log.clone(), generate_fn
640 /// );
641 /// assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid tuple");
642 ///
643 /// assert_eq!(log.0.lock().unwrap().clone(), vec![(5, 5), (5, 5)]);
644 /// ```
645 pub fn generate_result_with_state<
646 K: Serialize + Send + Sync + Any,
647 V: Serialize + DeserializeOwned + Send + Sync + Any,
648 E: Send + Sync + Any,
649 S: Send + Sync + Any,
650 >(
651 &mut self,
652 namespace: impl Into<Namespace>,
653 key: K,
654 state: S,
655 generate_fn: impl GenerateResultWithStateFn<K, S, V, E>,
656 ) -> CacheHandle<std::result::Result<V, E>> {
657 let namespace = namespace.into();
658 self.generate_result(namespace, key, move |k| generate_fn(k, state))
659 }
660
661 /// Gets a handle to a cacheable object from the cache, generating the object in the background
662 /// if needed.
663 ///
664 /// # Examples
665 ///
666 /// ```
667 /// use cache::{mem::NamespaceCache, error::Error, Cacheable};
668 /// use serde::{Deserialize, Serialize};
669 ///
670 /// #[derive(Deserialize, Serialize, Hash, Eq, PartialEq)]
671 /// pub struct Params {
672 /// param1: u64,
673 /// param2: String,
674 /// };
675 ///
676 /// impl Cacheable for Params {
677 /// type Output = u64;
678 /// type Error = anyhow::Error;
679 ///
680 /// fn generate(&self) -> anyhow::Result<u64> {
681 /// if self.param1 == 5 {
682 /// anyhow::bail!("invalid param");
683 /// } else if &self.param2 == "panic" {
684 /// panic!("unrecoverable param");
685 /// }
686 /// Ok(2 * self.param1)
687 /// }
688 /// }
689 ///
690 /// let mut cache = NamespaceCache::new();
691 ///
692 /// let handle = cache.get(
693 /// "example.namespace", Params { param1: 50, param2: "cache".to_string() }
694 /// );
695 /// assert_eq!(*handle.unwrap_inner(), 100);
696 ///
697 /// let handle = cache.get(
698 /// "example.namespace", Params { param1: 5, param2: "cache".to_string() }
699 /// );
700 /// assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid param");
701 ///
702 /// let handle = cache.get(
703 /// "example.namespace",Params { param1: 50, param2: "panic".to_string() }
704 /// );
705 /// assert!(matches!(handle.get_err().as_ref(), Error::Panic));
706 /// ```
707 pub fn get<K: Cacheable>(
708 &mut self,
709 namespace: impl Into<Namespace>,
710 key: K,
711 ) -> CacheHandle<std::result::Result<K::Output, K::Error>> {
712 let namespace = namespace.into();
713 self.generate_result(namespace, key, |key| key.generate())
714 }
715
716 /// Gets a handle to a cacheable object from the cache, caching failures as well.
717 ///
718 /// Generates the object in the background if needed.
719 ///
720 /// # Examples
721 ///
722 /// ```
723 /// use cache::{mem::NamespaceCache, error::Error, Cacheable};
724 /// use serde::{Deserialize, Serialize};
725 ///
726 /// #[derive(Deserialize, Serialize, Hash, Eq, PartialEq)]
727 /// pub struct Params {
728 /// param1: u64,
729 /// param2: String,
730 /// };
731 ///
732 /// impl Cacheable for Params {
733 /// type Output = u64;
734 /// type Error = bool;
735 ///
736 /// fn generate(&self) -> Result<Self::Output, Self::Error> {
737 /// if &self.param2 == "panic" {
738 /// panic!("unrecoverable param");
739 /// }
740 /// // Expensive computation...
741 /// # let computation_result = 5;
742 /// if computation_result == 5 {
743 /// return Err(false);
744 /// }
745 /// Ok(2 * self.param1)
746 /// }
747 /// }
748 ///
749 /// let mut cache = NamespaceCache::new();
750 ///
751 /// let handle = cache.get_with_err(
752 /// "example.namespace", Params { param1: 5, param2: "cache".to_string() }
753 /// );
754 /// assert_eq!(*handle.unwrap_err_inner(), false);
755 ///
756 /// // Does not need to carry out the expensive computation again as the error is cached.
757 /// let handle = cache.get_with_err(
758 /// "example.namespace", Params { param1: 5, param2: "cache".to_string() }
759 /// );
760 /// assert_eq!(*handle.unwrap_err_inner(), false);
761 /// ```
762 pub fn get_with_err<
763 E: Send + Sync + Serialize + DeserializeOwned + Any,
764 K: Cacheable<Error = E>,
765 >(
766 &mut self,
767 namespace: impl Into<Namespace>,
768 key: K,
769 ) -> CacheHandle<std::result::Result<K::Output, K::Error>> {
770 let namespace = namespace.into();
771 self.generate(namespace, key, |key| key.generate())
772 }
773
774 /// Gets a handle to a cacheable object from the cache, generating the object in the background
775 /// if needed.
776 ///
777 /// **Note:** The state is not used to determine whether the object should be regenerated. As
778 /// such, it should not impact the output of this function but rather should only be used to
779 /// store collateral or reuse computation from other function calls.
780 ///
781 /// However, the entries generated with different state types are not interchangeable. That is,
782 /// getting the same key with different states will regenerate the key several times, once for
783 /// each state type `S`.
784 ///
785 /// # Examples
786 ///
787 /// ```
788 /// use std::sync::{Arc, Mutex};
789 /// use cache::{mem::NamespaceCache, error::Error, CacheableWithState};
790 /// use serde::{Deserialize, Serialize};
791 ///
792 /// #[derive(Debug, Deserialize, Serialize, Clone, Hash, Eq, PartialEq)]
793 /// pub struct Params(u64);
794 ///
795 /// #[derive(Clone)]
796 /// pub struct Log(Arc<Mutex<Vec<Params>>>);
797 ///
798 /// impl CacheableWithState<Log> for Params {
799 /// type Output = u64;
800 /// type Error = anyhow::Error;
801 ///
802 /// fn generate_with_state(&self, state: Log) -> anyhow::Result<u64> {
803 /// println!("Logging parameters...");
804 /// state.0.lock().unwrap().push(self.clone());
805 ///
806 /// if self.0 == 5 {
807 /// anyhow::bail!("invalid param");
808 /// } else if self.0 == 8 {
809 /// panic!("unrecoverable param");
810 /// }
811 ///
812 /// Ok(2 * self.0)
813 /// }
814 /// }
815 ///
816 /// let mut cache = NamespaceCache::new();
817 /// let log = Log(Arc::new(Mutex::new(Vec::new())));
818 ///
819 /// let handle = cache.get_with_state(
820 /// "example.namespace",
821 /// Params(0),
822 /// log.clone(),
823 /// );
824 ///
825 /// assert_eq!(*handle.unwrap_inner(), 0);
826 ///
827 /// let handle = cache.get_with_state(
828 /// "example.namespace",
829 /// Params(5),
830 /// log.clone(),
831 /// );
832 ///
833 /// assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid param");
834 ///
835 /// let handle = cache.get_with_state(
836 /// "example.namespace",
837 /// Params(8),
838 /// log.clone(),
839 /// );
840 ///
841 /// assert!(matches!(handle.get_err().as_ref(), Error::Panic));
842 ///
843 /// assert_eq!(log.0.lock().unwrap().clone(), vec![Params(0), Params(5), Params(8)]);
844 /// ```
845 pub fn get_with_state<S: Send + Sync + Any, K: CacheableWithState<S>>(
846 &mut self,
847 namespace: impl Into<Namespace>,
848 key: K,
849 state: S,
850 ) -> CacheHandle<std::result::Result<K::Output, K::Error>> {
851 self.generate_result_with_state(namespace, key, state, |key, state| {
852 key.generate_with_state(state)
853 })
854 }
855
856 /// Gets a handle to a cacheable object from the cache, caching failures as well.
857 ///
858 /// Generates the object in the background if needed.
859 ///
860 /// See [`NamespaceCache::get_with_err`] and [`NamespaceCache::get_with_state`] for related examples.
861 pub fn get_with_state_and_err<
862 S: Send + Sync + Any,
863 E: Send + Sync + Serialize + DeserializeOwned + Any,
864 K: CacheableWithState<S, Error = E>,
865 >(
866 &mut self,
867 namespace: impl Into<Namespace>,
868 key: K,
869 state: S,
870 ) -> CacheHandle<std::result::Result<K::Output, K::Error>> {
871 let namespace = namespace.into();
872 self.generate_with_state(namespace, key, state, |key, state| {
873 key.generate_with_state(state)
874 })
875 }
876
877 pub(crate) fn generate_inner<
878 K: Serialize + Any + Send + Sync,
879 V: Serialize + DeserializeOwned + Send + Sync + Any,
880 >(
881 &mut self,
882 namespace: impl Into<Namespace>,
883 key: K,
884 generate_fn: impl GenerateFn<K, V>,
885 ) -> CacheHandleInner<V> {
886 let namespace = namespace.into();
887 self.generate_inner_dispatch(
888 namespace,
889 key,
890 generate_fn,
891 |value| Some(flexbuffers::to_vec(value).unwrap()),
892 |value| flexbuffers::from_slice(value).map_err(|e| Arc::new(e.into())),
893 )
894 }
895 pub(crate) fn generate_result_inner<
896 K: Serialize + Any + Send + Sync,
897 V: Serialize + DeserializeOwned + Send + Sync + Any,
898 E: Send + Sync + Any,
899 >(
900 &mut self,
901 namespace: impl Into<Namespace>,
902 key: K,
903 generate_fn: impl GenerateResultFn<K, V, E>,
904 ) -> CacheHandleInner<std::result::Result<V, E>> {
905 let namespace = namespace.into();
906 self.generate_inner_dispatch(
907 namespace,
908 key,
909 generate_fn,
910 |value| {
911 value
912 .as_ref()
913 .ok()
914 .map(|value| flexbuffers::to_vec(value).unwrap())
915 },
916 |value| {
917 flexbuffers::from_slice(value)
918 .map(|value| Ok(value))
919 .map_err(|e| Arc::new(e.into()))
920 },
921 )
922 }
923
924 fn generate_inner_dispatch<K: Serialize + Any + Send + Sync, V: Send + Sync + Any>(
925 &mut self,
926 namespace: Namespace,
927 key: K,
928 generate_fn: impl GenerateFn<K, V>,
929 serialize_value: impl SerializeValueFn<V>,
930 deserialize_value: impl DeserializeValueFn<V>,
931 ) -> CacheHandleInner<V> {
932 let handle = CacheHandleInner::default();
933 let hash = crate::hash(&flexbuffers::to_vec(&key).unwrap());
934
935 let (in_progress, entry) = match self.entries.entry(namespace).or_default().entry(hash) {
936 Entry::Vacant(v) => (false, v.insert(CacheHandleInner::default()).clone()),
937 Entry::Occupied(o) => (true, o.get().clone()),
938 }
939 .clone();
940
941 let entry2 = entry.clone();
942 let handle_clone = handle.clone();
943 thread::spawn(move || {
944 let value = if in_progress {
945 match entry.try_get() {
946 Ok(Some(value)) => Some(Ok(value)),
947 Ok(None) => None,
948 Err(e) => Some(Err(e)),
949 }
950 } else {
951 None
952 };
953 if let Some(value) = value {
954 handle_clone.set(value.and_then(|value| deserialize_value(value)));
955 } else {
956 let v = run_generator(move || generate_fn(&key));
957 if !in_progress {
958 entry2.set(v.as_ref().map(serialize_value).map_err(|e| e.clone()));
959 }
960 handle_clone.set(v);
961 }
962 });
963
964 handle
965 }
966}