1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
//! Caching utilities.
use std::{
any::Any,
sync::{Arc, Mutex},
};
use cache::{mem::TypeCache, multi::MultiCache, CacheHandle, Cacheable, CacheableWithState};
use serde::{de::DeserializeOwned, Serialize};
/// A cache with APIs for in-memory and persistent caching.
#[derive(Default, Debug, Clone)]
pub struct Cache {
inner: Arc<Mutex<CacheInner>>,
}
#[derive(Default, Debug)]
struct CacheInner {
type_cache: TypeCache,
cache: MultiCache,
}
impl Cache {
/// Creates a new [`Cache`] with the provided [`MultiCache`] configuration.
pub fn new(cache: MultiCache) -> Self {
Self {
inner: Arc::new(Mutex::new(CacheInner {
type_cache: TypeCache::new(),
cache,
})),
}
}
/// Gets a handle to a cacheable object from the cache, generating the object in the background
/// if needed.
///
/// If configured, persists data to disk.
///
/// Does not cache errors, so any errors thrown should be thrown quickly. Any errors that need
/// to be cached should be included in the cached output or should be cached using
/// [`Cache::get_with_err`].
pub fn get<K: Cacheable>(
&self,
namespace: impl Into<String>,
key: K,
) -> CacheHandle<Result<K::Output, K::Error>> {
let mut inner = self.inner.lock().unwrap();
inner.cache.get(namespace, key)
}
/// Gets a handle to a cacheable object from the cache, caching failures as well.
///
/// Generates the object in the background if needed and persists data to disk according to
/// configuration.
pub fn get_with_err<
E: Send + Sync + Serialize + DeserializeOwned + Any,
K: Cacheable<Error = E>,
>(
&self,
namespace: impl Into<String>,
key: K,
) -> CacheHandle<Result<K::Output, K::Error>> {
let mut inner = self.inner.lock().unwrap();
inner.cache.get_with_err(namespace, key)
}
/// Gets a handle to a cacheable object from the cache, generating the object in the background
/// if needed.
///
/// If configured, persists data to disk.
///
/// Does not cache errors, so any errors thrown should be thrown quickly. Any errors that need
/// to be cached should be included in the cached output or should be cached using
/// [`Cache::get_with_state_and_err`].
pub fn get_with_state<S: Send + Sync + Any, K: CacheableWithState<S>>(
&self,
namespace: impl Into<String>,
key: K,
state: S,
) -> CacheHandle<Result<K::Output, K::Error>> {
let mut inner = self.inner.lock().unwrap();
inner.cache.get_with_state(namespace, key, state)
}
/// Gets a handle to a cacheable object from the cache, caching failures as well.
///
/// Generates the object in the background if needed and persists data to disk according to
/// configuration.
///
/// See [`Cache::get_with_err`] and [`Cache::get_with_state`] for related examples.
pub fn get_with_state_and_err<
S: Send + Sync + Any,
E: Send + Sync + Serialize + DeserializeOwned + Any,
K: CacheableWithState<S, Error = E>,
>(
&self,
namespace: impl Into<String>,
key: K,
state: S,
) -> CacheHandle<Result<K::Output, K::Error>> {
let mut inner = self.inner.lock().unwrap();
inner.cache.get_with_state_and_err(namespace, key, state)
}
/// Gets a handle to a cacheable object from the cache, generating the object in the background
/// if needed.
///
/// Only caches data in memory.
pub fn type_get<K: Cacheable>(
&self,
key: K,
) -> CacheHandle<std::result::Result<K::Output, K::Error>> {
let mut inner = self.inner.lock().unwrap();
inner.type_cache.generate(key, |key| key.generate())
}
/// Gets a handle to a cacheable object from the cache, generating the object in the background
/// if needed.
///
/// Only caches data in memory.
///
/// **Note:** The state is not used to determine whether the object should be regenerated. As
/// such, it should not impact the output of this function but rather should only be used to
/// store collateral or reuse computation from other function calls.
///
/// However, the entries generated with different state types are not interchangeable. That is,
/// getting the same key with different states will regenerate the key several times, once for
/// each state type `S`.
pub fn type_get_with_state<S: Send + Sync + Any, K: CacheableWithState<S>>(
&self,
key: K,
state: S,
) -> CacheHandle<std::result::Result<K::Output, K::Error>> {
let mut inner = self.inner.lock().unwrap();
inner
.type_cache
.generate_with_state(key, state, |key, state| key.generate_with_state(state))
}
}