Caching structures and simplified function memoization
cached provides implementations of several caching structures as well as a handy macros
for defining memoized functions.
Memoized functions defined using #[cached]/#[once]/#[io_cached]/cached! macros are thread-safe with the backing
function-cache wrapped in a mutex/rwlock, or externally synchronized in the case of #[io_cached].
By default, the function-cache is not locked for the duration of the function's execution, so initial (on an empty cache)
concurrent calls of long-running functions with the same arguments will each execute fully and each overwrite
the memoized value as they complete. This mirrors the behavior of Python's functools.lru_cache. To synchronize the execution and caching
of un-cached arguments, specify #[cached(sync_writes = true)] / #[once(sync_writes = true)] (not supported by #[io_cached].
cached::stores docs cache stores available.proc_macro for more procedural macro examples.macros for more declarative macro examples.Features
default: Include proc_macro and async featuresproc_macro: Include proc macrosasync: Include support for async functions and async cache storesredis_store: Include Redis cache storeredis_async_std: Include async Redis support using async-std and async-std tls support, implies redis_store and asyncredis_tokio: Include async Redis support using tokio and tokio tls support, implies redis_store and asyncwasm: Enable WASM support. Note that this feature is incompatible with all Redis features (redis_store, redis_async_std, redis_tokio)The procedural macros (#[cached], #[once], #[io_cached]) offer more features, including async support.
See the proc_macro and macros modules for more samples, and the
examples directory for runnable snippets.`
Any custom cache that implements cached::Cached/cached::CachedAsync can be used with the #[cached]/#[once]/cached! macros in place of the built-ins.
Any custom cache that implements cached::IOCached/cached::IOCachedAsync can be used with the #[io_cached] macro.
The basic usage looks like:
```rust use cached::proc_macro::cached;
/// Defines a function named fib that uses a cache implicitly named FIB.
/// By default, the cache will be the function's name in all caps.
/// The following line is equivalent to #[cached(name = "FIB", unbound)]
fn fib(n: u64) -> u64 { if n == 0 || n == 1 { return n } fib(n-1) + fib(n-2) } ```
```rust use std::thread::sleep; use std::time::Duration; use cached::proc_macro::cached; use cached::SizedCache;
/// Use an explicit cache-type with a custom creation block and custom cache-key generating block
type = "SizedCache<String, usize>",
create = "{ SizedCache::with_size(100) }",
convert = r#"{ format!("{}{}", a, b) }"#
)] fn keyed(a: &str, b: &str) -> usize { let size = a.len() + b.len(); sleep(Duration::new(size as u64, 0)); size } ```
```rust use cached::proc_macro::once;
/// Only cache the initial function call.
/// Function will be re-executed after the cache
/// expires (according to time seconds).
/// When no (or expired) cache, concurrent calls
/// will synchronize (sync_writes) so the function
/// is only executed once.
fn keyed(a: String) -> Option
```rust,norun,ignore use cached::procmacro::io_cached; use cached::AsyncRedisCache; use thiserror::Error;
enum ExampleError {
#[error("error with redis cache {0}")]
RedisError(String),
}
/// Cache the results of an async function in redis. Cache
/// keys will be prefixed with cache_redis_prefix.
/// A map_error closure must be specified to convert any
/// redis cache errors into the same type of error returned
/// by your function. All io_cached functions must return Results.
map_error = r##"|e| ExampleError::RedisError(format!("{:?}", e))"##,
type = "AsyncRedisCache<u64, String>",
create = r##" {
AsyncRedisCache::new("cached_redis_prefix", 1)
.set_refresh(true)
.build()
.await
.expect("error building example redis cache")
} "##
)]
async fn asynccachedsleepsecs(secs: u64) -> Result
Functions defined via macros will have their results cached using the
function's arguments as a key, a convert expression specified on a procedural macros,
or a Key block specified on a cached_key! declarative macro.
When a macro-defined function is called, the function's cache is first checked for an already computed (and still valid) value before evaluating the function body.
Due to the requirements of storing arguments and return values in a global cache:
Cloneserde::Serialize + serde::DeserializeOwnedHash + Eq + Clone,
the cached_key! macro is used with a Key block specifying key construction, or
a convert expression is specified on a procedural macro to specify how to construct a key
of a Hash + Eq + Clone type.Display, or the cached_key! & Key
or procedural macro & convert expression used to specify how to construct a key of a Display type.cloned in the process of insertion and retrieval. Except for Redis
where arguments are formatted into Strings and values are de/serialized.impl blocks since macros expand to a
once_cell/lazy_static initialization and one or more function definitions.Self types as a parameter.License: MIT