3 unstable releases

new 0.2.0 Oct 17, 2024
0.1.1 Oct 14, 2024
0.1.0 Oct 14, 2024

#52 in Caching

Download history 215/week @ 2024-10-09

215 downloads per month

MIT license

74KB
1.5K SLoC

Kash

Build Status crates.io docs

Caching structures and simplified function memoization, using #[kash] macro.

use kash::kash;

/// 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.
#[kash]
fn fib(n: u64) -> u64 {
    if n == 0 || n == 1 { return n }
    fib(n-1) + fib(n-2)
}

Or if you want to limit the size and time-to-live:

use kash::kash;

const TTL: u64 = 1000;
#[kash(size = "100", ttl = "TTL")]
fn fib(n: u64) -> u64 {
    if n == 0 || n == 1 { return n }
    fib(n-1) + fib(n-2)
}

Features

  • default: Includes ahash feature.
  • ahash: Enable ahash hasher as default hashing algorithm.
  • async: Include support for async functions.
  • redis_store: Include Redis cache store.
  • redis_async_std: Include async Redis support using async-std and async-std tls support, implies redis_store and async.
  • redis_tokio: Include async Redis support using tokio and tokio tls support, implies redis_store and async.
  • redis_connection_manager: Enable the optional connection-manager feature of redis. Any async redis caches created will use a connection manager instead of a MultiplexedConnection.
  • redis_ahash: Enable the optional ahash feature of redis.
  • disk_store: Include disk cache store.

use std::thread::sleep;
use std::time::Duration;
use kash::kash;

/// Use an explicit cache-type with a custom creation block and custom cache-key generating block
#[kash(
    size = "100",
    key(ty = "String", expr = 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
}

use kash::{kash, RedisCacheError};
use kash::AsyncRedisCache;
use thiserror::Error;

#[derive(Error, Debug, PartialEq, Clone)]
enum ExampleError {
    #[error("error with redis cache `{0}`")]
    RedisError(String),
}

impl From<RedisCacheError> for ExampleError {
    fn from(e: RedisCacheError) -> Self {
        ExampleError::RedisError(format!("{:?}", e))
    }
}

/// Cache the results of an async function in redis. Cache
/// keys will be prefixed with `cache_redis_prefix`.
#[kash(redis)]
async fn async_kash_sleep_secs(secs: u64) -> Result<String, ExampleError> {
    std::thread::sleep(std::time::Duration::from_secs(secs));
    Ok(secs.to_string())
}

use kash::{kash, DiskCacheError};
use kash::DiskCache;
use thiserror::Error;

#[derive(Error, Debug, PartialEq, Clone)]
enum ExampleError {
    #[error("error with disk cache `{0}`")]
    DiskError(String),
}

impl From<DiskCacheError> for ExampleError {
    fn from(e: DiskCacheError) -> Self {
        ExampleError::DiskError(format!("{:?}", e))
    }
}

/// Cache the results of a function on disk.
/// Cache files will be stored under the system cache dir
/// unless otherwise specified with `dir` or the `create` argument.
#[kash(disk)]
fn kash_sleep_secs(secs: u64) -> Result<String, ExampleError> {
    std::thread::sleep(std::time::Duration::from_secs(secs));
    Ok(secs.to_string())
}

Functions defined via macros will have their result, cached using the function's arguments as a key by default.

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.

See examples directory for more examples.

License

MIT

Dependencies

~4–17MB
~249K SLoC