kash/lib.rs
1/*!
2[](https://crates.io/crates/kash)
3
4[](https://crates.io/crates/kash)
5[](https://docs.rs/kash)
6
7[](https://deps.rs/crate/kash)
8
9Function and method cache and memoization library for Rust, using [`#[kash]`](kash) macro.
10
11```rust
12use kash::kash;
13
14/// Defines a function named `fib` that uses a cache implicitly named `FIB`.
15/// By default, the cache will be the function's name in all caps.
16#[kash]
17fn fib(n: u64) -> u64 {
18 if n == 0 || n == 1 { return n }
19 fib(n-1) + fib(n-2)
20}
21```
22
23Or if you want to limit the size and time-to-live:
24
25```rust
26use kash::kash;
27
28const TTL: u64 = 1000;
29#[kash(size = "100", ttl = "TTL")]
30fn fib(n: u64) -> u64 {
31 if n == 0 || n == 1 { return n }
32 fib(n-1) + fib(n-2)
33}
34```
35
36## Features
37
38- `default`: Includes `ahash` feature.
39- `ahash`: Enable `ahash` hasher as default hashing algorithm.
40- `async`: Include support for async functions.
41- `redis_store`: Include Redis cache store.
42- `redis_tokio`: Include async Redis support using `tokio` and `tokio` tls support, implies `redis_store` and `async`.
43- `redis_connection_manager`: Enable the optional `connection-manager` feature of `redis`. Any async redis caches created
44 will use a connection manager instead of a `MultiplexedConnection`.
45- `redis_ahash`: Enable the optional `ahash` feature of `redis`.
46- `disk_store`: Include disk cache store.
47
48----
49
50```rust
51use std::thread::sleep;
52use std::time::Duration;
53use kash::kash;
54
55/// Use an explicit cache-type with a custom creation block and custom cache-key generating block
56#[kash(
57 size = "100",
58 key(ty = "String", expr = r#"{ format!("{}{}", a, b) }"#)
59)]
60fn keyed(a: &str, b: &str) -> usize {
61 let size = a.len() + b.len();
62 sleep(Duration::new(size as u64, 0));
63 size
64}
65# pub fn main() { }
66```
67
68----
69
70```rust
71use kash::{kash, RedisCacheError};
72use kash::AsyncRedisCache;
73use thiserror::Error;
74
75#[derive(Error, Debug, PartialEq, Clone)]
76enum ExampleError {
77 #[error("error with redis cache `{0}`")]
78 RedisError(String),
79}
80
81impl From<RedisCacheError> for ExampleError {
82 fn from(e: RedisCacheError) -> Self {
83 ExampleError::RedisError(format!("{:?}", e))
84 }
85}
86
87/// Cache the results of an async function in redis. Cache
88/// keys will be prefixed with `cache_redis_prefix`.
89#[kash(redis)]
90async fn async_kash_sleep_secs(secs: u64) -> Result<String, ExampleError> {
91 std::thread::sleep(std::time::Duration::from_secs(secs));
92 Ok(secs.to_string())
93}
94```
95
96----
97
98```rust
99use kash::{kash, DiskCacheError};
100use kash::DiskCache;
101use thiserror::Error;
102
103#[derive(Error, Debug, PartialEq, Clone)]
104enum ExampleError {
105 #[error("error with disk cache `{0}`")]
106 DiskError(String),
107}
108
109impl From<DiskCacheError> for ExampleError {
110 fn from(e: DiskCacheError) -> Self {
111 ExampleError::DiskError(format!("{:?}", e))
112 }
113}
114
115/// Cache the results of a function on disk.
116/// Cache files will be stored under the system cache dir
117/// unless otherwise specified with `dir` or the `create` argument.
118#[kash(disk)]
119fn kash_sleep_secs(secs: u64) -> Result<String, ExampleError> {
120 std::thread::sleep(std::time::Duration::from_secs(secs));
121 Ok(secs.to_string())
122}
123```
124
125Functions defined via macros will have their result, cached using the
126function's arguments as a key by default.
127
128When a macro-defined function is called, the function's cache is first checked for an already
129computed (and still valid) value before evaluating the function body.
130
131See [`examples`](https://github.com/omid/kash/tree/master/examples) directory for more examples.
132*/
133
134#![cfg_attr(docsrs, feature(doc_cfg))]
135
136#[doc(hidden)]
137pub use moka;
138#[doc(hidden)]
139pub use once_cell;
140
141#[cfg(feature = "async")]
142use async_trait::async_trait;
143
144#[doc(inline)]
145pub use kash_macros::kash;
146
147#[cfg(feature = "redis_tokio")]
148#[cfg_attr(docsrs, doc(cfg(feature = "redis_tokio")))]
149pub use stores::AsyncRedisCache;
150#[cfg(feature = "disk_store")]
151#[cfg_attr(docsrs, doc(cfg(feature = "disk_store")))]
152pub use stores::{DiskCache, DiskCacheError};
153#[cfg(feature = "redis_store")]
154#[cfg_attr(docsrs, doc(cfg(feature = "redis_store")))]
155pub use stores::{RedisCache, RedisCacheError};
156
157pub mod stores;
158#[doc(hidden)]
159pub use instant;
160
161#[cfg(feature = "tokio")]
162#[doc(hidden)]
163pub mod async_sync {
164 pub use tokio::sync::Mutex;
165 pub use tokio::sync::OnceCell;
166 pub use tokio::sync::RwLock;
167}
168
169/// Cache operations on an io-connected store
170pub trait IOKash<K, V> {
171 type Error;
172
173 /// Attempt to retrieve a cached value
174 ///
175 /// # Errors
176 ///
177 /// Should return `Self::Error` if the operation fails
178 fn get(&self, k: &K) -> Result<Option<V>, Self::Error>;
179
180 /// Insert a key, value pair and return the previous value
181 ///
182 /// # Errors
183 ///
184 /// Should return `Self::Error` if the operation fails
185 fn set(&self, k: K, v: V) -> Result<Option<V>, Self::Error>;
186
187 /// Remove a cached value
188 ///
189 /// # Errors
190 ///
191 /// Should return `Self::Error` if the operation fails
192 fn remove(&self, k: &K) -> Result<Option<V>, Self::Error>;
193
194 /// Remove all cached values
195 ///
196 /// # Errors
197 ///
198 /// Should return `Self::Error` if the operation fails
199 fn clear(&self) -> Result<(), Self::Error>;
200
201 /// Return the ttl of cached values (time to eviction)
202 fn ttl(&self) -> Option<u64> {
203 None
204 }
205
206 /// Set the ttl of cached values, returns the old value.
207 fn set_ttl(&mut self, _seconds: u64) -> Option<u64> {
208 None
209 }
210
211 /// Remove the ttl for cached values, returns the old value.
212 ///
213 /// For cache implementations that don't support retaining values indefinitely, this method is
214 /// a no-op.
215 fn unset_ttl(&mut self) -> Option<u64> {
216 None
217 }
218}
219
220#[cfg(feature = "async")]
221#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
222#[async_trait]
223pub trait IOKashAsync<K, V> {
224 type Error;
225 async fn get(&self, k: &K) -> Result<Option<V>, Self::Error>;
226
227 async fn set(&self, k: K, v: V) -> Result<Option<V>, Self::Error>;
228
229 /// Remove a cached value
230 async fn remove(&self, k: &K) -> Result<Option<V>, Self::Error>;
231
232 /// Remove all cached values
233 async fn clear(&self) -> Result<(), Self::Error>;
234
235 /// Return the ttl of cached values (time to eviction)
236 fn ttl(&self) -> Option<u64> {
237 None
238 }
239
240 /// Set the ttl of cached values, returns the old value
241 fn set_ttl(&mut self, _seconds: u64) -> Option<u64> {
242 None
243 }
244
245 /// Remove the ttl for cached values, returns the old value.
246 ///
247 /// For cache implementations that don't support retaining values indefinitely, this method is
248 /// a no-op.
249 fn unset_ttl(&mut self) -> Option<u64> {
250 None
251 }
252}