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

source

pub fn new() -> Self

Creates a new cache.

source

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);
source

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)]);
source

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");
source

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)]);
source

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));
source

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);
source

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)]);
source

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

source§

fn clone(&self) -> NamespaceCache

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for NamespaceCache

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for NamespaceCache

source§

fn default() -> NamespaceCache

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> FromRef<T> for T
where T: Clone,

§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoRequest<T> for T

source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more