threatflux-cache 0.2.0

A bounded async cache library with in-memory and filesystem backends
Documentation

ThreatFlux Cache

Crates.io docs.rs CI Security CodeQL MSRV License

An async, typed cache for Rust applications that need pluggable storage, bounded key histories, metadata, and simple entry queries.

ThreatFlux Cache keeps its working set in memory. Applications can use the built-in memory backend, enable filesystem snapshots, or implement StorageBackend for another persistence mechanism.

Highlights

  • Generic, serializable keys, values, and metadata
  • put semantics for one current value per key
  • add_entry semantics for bounded per-key history
  • LRU, LFU, FIFO, TTL, and manual eviction strategies
  • Timestamp, access-count, key-pattern, and metadata-category filters
  • Bounded, versioned JSON filesystem snapshots
  • An async API built on Tokio with no unsafe code in the crate

Install

The default features enable the filesystem backend and JSON serialization. The default cache type still uses the in-memory backend unless you construct a FilesystemBackend explicitly.

[dependencies]
threatflux-cache = "0.2.0"
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

For a memory-only build:

[dependencies]
threatflux-cache = { version = "0.2.0", default-features = false }
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

ThreatFlux Cache requires Rust 1.95.0 or newer.

Quick start

use serde::{Deserialize, Serialize};
use threatflux_cache::{AsyncCache, Cache, CacheConfig};

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
struct User {
    id: u64,
    name: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cache: Cache<String, User> = Cache::with_config(CacheConfig::default()).await?;
    let key = "user:1".to_owned();

    cache
        .put(
            key.clone(),
            User {
                id: 1,
                name: "Alice".to_owned(),
            },
        )
        .await?;

    assert_eq!(
        cache.get(&key).await?.map(|user| user.name),
        Some("Alice".to_owned())
    );
    Ok(())
}

put replaces the history for its key. Use CacheEntry and add_entry when you want to retain multiple versions:

use threatflux_cache::{Cache, CacheConfig, CacheEntry};

# async fn example() -> threatflux_cache::Result<()> {
let cache: Cache<String, String> = Cache::with_config(
    CacheConfig::default().with_max_entries_per_key(3),
)
.await?;

cache
    .add_entry(CacheEntry::new("report".to_owned(), "version 1".to_owned()))
    .await?;
cache
    .add_entry(CacheEntry::new("report".to_owned(), "version 2".to_owned()))
    .await?;

assert_eq!(cache.get_entries(&"report".to_owned()).await.unwrap().len(), 2);
# Ok(())
# }

See examples/basic_usage.rs and examples/custom_entry.rs for complete programs.

Filesystem snapshots

Filesystem persistence requires the filesystem-backend feature. The backend path is authoritative; configure persistence separately so the cache loads and saves snapshots.

use threatflux_cache::{
    AsyncCache, Cache, CacheConfig, FilesystemBackend, PersistenceConfig,
};

# async fn example() -> threatflux_cache::Result<()> {
let path = std::path::PathBuf::from("./cache-data");
let backend = FilesystemBackend::<String, String>::new(&path).await?;
let config = CacheConfig::default()
    .with_persistence(PersistenceConfig::enabled());
let cache = Cache::new(config, backend).await?;
cache.put("greeting".to_owned(), "hello".to_owned()).await?;
cache.flush().await?;
# Ok(())
# }

flush waits for the backend to finish writing the current state. Snapshots are not a transactional database or substitute for a system of record. Read docs/PERSISTENCE.md before relying on restart recovery or sharing a directory between processes.

Feature flags

Feature Default Surface enabled
filesystem-backend yes FilesystemBackend; also enables Tokio filesystem I/O and JSON serialization
full no Alias for every supported optional feature

For tested feature combinations and current limitations, see docs/FEATURES.md.

Behavioral boundaries

  • get returns the newest entry and records an access; get_entries records an access for every returned version.
  • Search patterns are case-sensitive substrings of the key's Display output; values are not full-text searched.
  • get, get_entries, contains, len, and search exclude expired entries; search can opt into expired results.
  • LRU, LFU, and FIFO eviction remove one entire key and its history when the global limit is crossed.
  • default_ttl applies to entries that do not already have an explicit expiry.
  • Zero entry limits and a zero persistence sync interval are rejected; with eviction disabled, an insertion that would grow a full cache returns CapacityExceeded.

The complete contract is documented in docs/BEHAVIOR.md. This crate is pre-1.0; minor releases may refine APIs and on-disk representation.

Extending the cache

Implement StorageBackend to provide a different snapshot store. Implement EntryMetadata to attach domain-specific metadata and expose a category to the built-in search filters.

Development and security

License

Licensed under the MIT License.