Struct cache::mem::NamespaceCache
source · pub struct NamespaceCache { /* private fields */ }
Expand description
An in-memory cache based on namespace strings and types that implement Serialize
and
Deserialize
.
Unlike a TypeCache
, a NamespaceCache
works by serializing and deserializing keys and
values. As such, an entry can be accessed with several generic types as long as all of the
types serialize/deserialize to/from the same bytes.
Implementations§
source§impl NamespaceCache
impl NamespaceCache
sourcepub fn generate<K: Serialize + Any + Send + Sync, V: Serialize + DeserializeOwned + Send + Sync + Any>(
&mut self,
namespace: impl Into<Namespace>,
key: K,
generate_fn: impl GenerateFn<K, V>
) -> CacheHandle<V>
pub fn generate<K: Serialize + Any + Send + Sync, V: Serialize + DeserializeOwned + Send + Sync + Any>( &mut self, namespace: impl Into<Namespace>, key: K, generate_fn: impl GenerateFn<K, V> ) -> CacheHandle<V>
Ensures that a value corresponding to key
is generated, using generate_fn
to generate it if it has not already been generated.
A more general counterpart to NamespaceCache::get
.
Returns a handle to the value. If the value is not yet generated, it is generated in the background.
§Panics
Panics if a different type V
or E
is already associated with type K
.
§Examples
use cache::{mem::NamespaceCache, error::Error, CacheableWithState};
let mut cache = NamespaceCache::new();
fn generate_fn(tuple: &(u64, u64)) -> u64 {
tuple.0 + tuple.1
}
fn generate_fn2(tuple: &(u64, u64)) -> u64 {
tuple.0 * tuple.1
}
let handle = cache.generate("example.namespace", (5, 6), generate_fn);
assert_eq!(*handle.get(), 11);
// Does not call `generate_fn` again as the result has been cached.
let handle = cache.generate("example.namespace", (5, 6), generate_fn);
assert_eq!(*handle.get(), 11);
// Calls the new `generate_fn2` as the namespace is different,
// even though the key is the same.
let handle = cache.generate("example.namespace2", (5, 6), generate_fn2);
assert_eq!(*handle.get(), 30);
sourcepub fn generate_with_state<K: Serialize + Any + Send + Sync, V: Serialize + DeserializeOwned + Send + Sync + Any, S: Send + Sync + Any>(
&mut self,
namespace: impl Into<Namespace>,
key: K,
state: S,
generate_fn: impl GenerateWithStateFn<K, S, V>
) -> CacheHandle<V>
pub fn generate_with_state<K: Serialize + Any + Send + Sync, V: Serialize + DeserializeOwned + Send + Sync + Any, S: Send + Sync + Any>( &mut self, namespace: impl Into<Namespace>, key: K, state: S, generate_fn: impl GenerateWithStateFn<K, S, V> ) -> CacheHandle<V>
Ensures that a value corresponding to key
is generated, using generate_fn
to generate it if it has not already been generated.
A more general counterpart to NamespaceCache::get_with_state
.
Returns a handle to the value. If the value is not yet generated, it is generated in the background.
§Panics
Panics if a different type V
or E
is already associated with type K
.
§Examples
use std::sync::{Arc, Mutex};
use cache::{mem::NamespaceCache, error::Error, CacheableWithState};
#[derive(Clone)]
pub struct Log(Arc<Mutex<Vec<(u64, u64)>>>);
let mut cache = NamespaceCache::new();
let log = Log(Arc::new(Mutex::new(Vec::new())));
fn generate_fn(tuple: &(u64, u64), state: Log) -> u64 {
println!("Logging parameters...");
state.0.lock().unwrap().push(*tuple);
tuple.0 + tuple.1
}
let handle = cache.generate_with_state("example.namespace", (5, 6), log.clone(), generate_fn);
assert_eq!(*handle.get(), 11);
// Does not call `generate_fn` again as the result has been cached.
let handle = cache.generate_with_state("example.namespace", (5, 6), log.clone(), generate_fn);
assert_eq!(*handle.get(), 11);
assert_eq!(log.0.lock().unwrap().clone(), vec![(5, 6)]);
sourcepub fn generate_result<K: Serialize + Any + Send + Sync, V: Serialize + DeserializeOwned + Send + Sync + Any, E: Send + Sync + Any>(
&mut self,
namespace: impl Into<Namespace>,
key: K,
generate_fn: impl GenerateResultFn<K, V, E>
) -> CacheHandle<Result<V, E>>
pub fn generate_result<K: Serialize + Any + Send + Sync, V: Serialize + DeserializeOwned + Send + Sync + Any, E: Send + Sync + Any>( &mut self, namespace: impl Into<Namespace>, key: K, generate_fn: impl GenerateResultFn<K, V, E> ) -> CacheHandle<Result<V, E>>
Ensures that a result corresponding to key
is generated, using generate_fn
to generate it if it has not already been generated.
Does not cache on failure as errors are not constrained to be serializable/deserializable.
As such, failures should happen quickly, or should be serializable and stored as part of
cached value using NamespaceCache::generate
.
Returns a handle to the value. If the value is not yet generated, it is generated
§Examples
use cache::{mem::NamespaceCache, error::Error, Cacheable};
let mut cache = NamespaceCache::new();
fn generate_fn(tuple: &(u64, u64)) -> anyhow::Result<u64> {
if *tuple == (5, 5) {
Err(anyhow::anyhow!("invalid tuple"))
} else {
Ok(tuple.0 + tuple.1)
}
}
let handle = cache.generate_result("example.namespace", (5, 5), generate_fn);
assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid tuple");
// Calls `generate_fn` again as the error was not cached.
let handle = cache.generate_result("example.namespace", (5, 5), generate_fn);
assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid tuple");
sourcepub fn generate_result_with_state<K: Serialize + Send + Sync + Any, V: Serialize + DeserializeOwned + Send + Sync + Any, E: Send + Sync + Any, S: Send + Sync + Any>(
&mut self,
namespace: impl Into<Namespace>,
key: K,
state: S,
generate_fn: impl GenerateResultWithStateFn<K, S, V, E>
) -> CacheHandle<Result<V, E>>
pub fn generate_result_with_state<K: Serialize + Send + Sync + Any, V: Serialize + DeserializeOwned + Send + Sync + Any, E: Send + Sync + Any, S: Send + Sync + Any>( &mut self, namespace: impl Into<Namespace>, key: K, state: S, generate_fn: impl GenerateResultWithStateFn<K, S, V, E> ) -> CacheHandle<Result<V, E>>
Ensures that a value corresponding to key
is generated, using generate_fn
to generate it if it has not already been generated.
Does not cache on failure as errors are not constrained to be serializable/deserializable.
As such, failures should happen quickly, or should be serializable and stored as part of
cached value using NamespaceCache::generate_with_state
.
Returns a handle to the value. If the value is not yet generated, it is generated in the background.
§Examples
use std::sync::{Arc, Mutex};
use cache::{mem::NamespaceCache, error::Error, Cacheable};
#[derive(Clone)]
pub struct Log(Arc<Mutex<Vec<(u64, u64)>>>);
let mut cache = NamespaceCache::new();
let log = Log(Arc::new(Mutex::new(Vec::new())));
fn generate_fn(tuple: &(u64, u64), state: Log) -> anyhow::Result<u64> {
println!("Logging parameters...");
state.0.lock().unwrap().push(*tuple);
if *tuple == (5, 5) {
Err(anyhow::anyhow!("invalid tuple"))
} else {
Ok(tuple.0 + tuple.1)
}
}
let handle = cache.generate_result_with_state(
"example.namespace", (5, 5), log.clone(), generate_fn
);
assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid tuple");
// Calls `generate_fn` again as the error was not cached.
let handle = cache.generate_result_with_state(
"example.namespace", (5, 5), log.clone(), generate_fn
);
assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid tuple");
assert_eq!(log.0.lock().unwrap().clone(), vec![(5, 5), (5, 5)]);
sourcepub fn get<K: Cacheable>(
&mut self,
namespace: impl Into<Namespace>,
key: K
) -> CacheHandle<Result<K::Output, K::Error>>
pub fn get<K: Cacheable>( &mut self, namespace: impl Into<Namespace>, key: K ) -> CacheHandle<Result<K::Output, K::Error>>
Gets a handle to a cacheable object from the cache, generating the object in the background if needed.
§Examples
use cache::{mem::NamespaceCache, error::Error, Cacheable};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Hash, Eq, PartialEq)]
pub struct Params {
param1: u64,
param2: String,
};
impl Cacheable for Params {
type Output = u64;
type Error = anyhow::Error;
fn generate(&self) -> anyhow::Result<u64> {
if self.param1 == 5 {
anyhow::bail!("invalid param");
} else if &self.param2 == "panic" {
panic!("unrecoverable param");
}
Ok(2 * self.param1)
}
}
let mut cache = NamespaceCache::new();
let handle = cache.get(
"example.namespace", Params { param1: 50, param2: "cache".to_string() }
);
assert_eq!(*handle.unwrap_inner(), 100);
let handle = cache.get(
"example.namespace", Params { param1: 5, param2: "cache".to_string() }
);
assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid param");
let handle = cache.get(
"example.namespace",Params { param1: 50, param2: "panic".to_string() }
);
assert!(matches!(handle.get_err().as_ref(), Error::Panic));
sourcepub fn get_with_err<E: Send + Sync + Serialize + DeserializeOwned + Any, K: Cacheable<Error = E>>(
&mut self,
namespace: impl Into<Namespace>,
key: K
) -> CacheHandle<Result<K::Output, K::Error>>
pub fn get_with_err<E: Send + Sync + Serialize + DeserializeOwned + Any, K: Cacheable<Error = E>>( &mut self, namespace: impl Into<Namespace>, key: K ) -> CacheHandle<Result<K::Output, K::Error>>
Gets a handle to a cacheable object from the cache, caching failures as well.
Generates the object in the background if needed.
§Examples
use cache::{mem::NamespaceCache, error::Error, Cacheable};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Hash, Eq, PartialEq)]
pub struct Params {
param1: u64,
param2: String,
};
impl Cacheable for Params {
type Output = u64;
type Error = bool;
fn generate(&self) -> Result<Self::Output, Self::Error> {
if &self.param2 == "panic" {
panic!("unrecoverable param");
}
// Expensive computation...
if computation_result == 5 {
return Err(false);
}
Ok(2 * self.param1)
}
}
let mut cache = NamespaceCache::new();
let handle = cache.get_with_err(
"example.namespace", Params { param1: 5, param2: "cache".to_string() }
);
assert_eq!(*handle.unwrap_err_inner(), false);
// Does not need to carry out the expensive computation again as the error is cached.
let handle = cache.get_with_err(
"example.namespace", Params { param1: 5, param2: "cache".to_string() }
);
assert_eq!(*handle.unwrap_err_inner(), false);
sourcepub fn get_with_state<S: Send + Sync + Any, K: CacheableWithState<S>>(
&mut self,
namespace: impl Into<Namespace>,
key: K,
state: S
) -> CacheHandle<Result<K::Output, K::Error>>
pub fn get_with_state<S: Send + Sync + Any, K: CacheableWithState<S>>( &mut self, namespace: impl Into<Namespace>, key: K, state: S ) -> CacheHandle<Result<K::Output, K::Error>>
Gets a handle to a cacheable object from the cache, generating the object in the background if needed.
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
.
§Examples
use std::sync::{Arc, Mutex};
use cache::{mem::NamespaceCache, error::Error, CacheableWithState};
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Clone, Hash, Eq, PartialEq)]
pub struct Params(u64);
#[derive(Clone)]
pub struct Log(Arc<Mutex<Vec<Params>>>);
impl CacheableWithState<Log> for Params {
type Output = u64;
type Error = anyhow::Error;
fn generate_with_state(&self, state: Log) -> anyhow::Result<u64> {
println!("Logging parameters...");
state.0.lock().unwrap().push(self.clone());
if self.0 == 5 {
anyhow::bail!("invalid param");
} else if self.0 == 8 {
panic!("unrecoverable param");
}
Ok(2 * self.0)
}
}
let mut cache = NamespaceCache::new();
let log = Log(Arc::new(Mutex::new(Vec::new())));
let handle = cache.get_with_state(
"example.namespace",
Params(0),
log.clone(),
);
assert_eq!(*handle.unwrap_inner(), 0);
let handle = cache.get_with_state(
"example.namespace",
Params(5),
log.clone(),
);
assert_eq!(format!("{}", handle.unwrap_err_inner().root_cause()), "invalid param");
let handle = cache.get_with_state(
"example.namespace",
Params(8),
log.clone(),
);
assert!(matches!(handle.get_err().as_ref(), Error::Panic));
assert_eq!(log.0.lock().unwrap().clone(), vec![Params(0), Params(5), Params(8)]);
sourcepub fn get_with_state_and_err<S: Send + Sync + Any, E: Send + Sync + Serialize + DeserializeOwned + Any, K: CacheableWithState<S, Error = E>>(
&mut self,
namespace: impl Into<Namespace>,
key: K,
state: S
) -> CacheHandle<Result<K::Output, K::Error>>
pub fn get_with_state_and_err<S: Send + Sync + Any, E: Send + Sync + Serialize + DeserializeOwned + Any, K: CacheableWithState<S, Error = E>>( &mut self, namespace: impl Into<Namespace>, key: K, state: S ) -> CacheHandle<Result<K::Output, K::Error>>
Gets a handle to a cacheable object from the cache, caching failures as well.
Generates the object in the background if needed.
See NamespaceCache::get_with_err
and NamespaceCache::get_with_state
for related examples.
Trait Implementations§
source§impl Clone for NamespaceCache
impl Clone for NamespaceCache
source§fn clone(&self) -> NamespaceCache
fn clone(&self) -> NamespaceCache
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl Debug for NamespaceCache
impl Debug for NamespaceCache
source§impl Default for NamespaceCache
impl Default for NamespaceCache
source§fn default() -> NamespaceCache
fn default() -> NamespaceCache
Auto Trait Implementations§
impl !RefUnwindSafe for NamespaceCache
impl Send for NamespaceCache
impl Sync for NamespaceCache
impl Unpin for NamespaceCache
impl !UnwindSafe for NamespaceCache
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T
in a tonic::Request