sassi
Named after Sassi and Punnu, the central figures of a classic Punjabi folk tale.
Sassi is a typed cache substrate for Rust applications.
It helps you keep a local, typed view of data you have already fetched without tying that view to an ORM, a web framework, or a database client. A service, worker, desktop app, library, or WASM build can use the same data model and the same cache contracts.
The name is meant in that literary context. If it is unfamiliar, the source material is worth exploring on its own terms; this project borrows from that tradition, not from an acronym or an invented technical metaphor. Any similarity to unrelated software, tools, or projects is coincidental. Sassi is independent and unaffiliated.
Why Sassi Exists
Many Rust applications grow a layer between the source of truth and the code that reads from it: identity maps, predicate helpers, refresh tasks, backend invalidation, and small caches around expensive calls. Those layers often start simple. The hard parts tend to arrive gradually: typed identity, freshness, eviction, query boundaries, runtime portability, and visibility into what the cache is doing.
Sassi gives that layer a shared shape. It is not trying to replace a database, an ORM, or an application state framework. It focuses on the cache substrate beneath them: storing values by typed identity, reading through explicit predicates, refreshing from fetchers, and keeping cache policy visible in Rust types.
What It Provides
- Typed identity maps through
Punnu<T>andCacheable - Cheap in-process reads from immutable L1 snapshots
BasicPredicate<T>for constraints a fetcher can inspect and replayMemQ<T>for in-memory closure and trait-based querying- Lazy fetch-on-miss with
get_or_fetchandget_or_fetch_many - Periodic refresh and watermark-based delta refresh
- Bounded sampled-LRU eviction, optional TTL, events, and metrics
- An L2
CacheBackendboundary with memory and file backends in the core crate - Redis support in the
sassi-cache-rediscompanion crate - A
Sassiorchestrator for typed pools and cross-type trait queries - Native
tokiosupport and awasm32-unknown-unknowncompile path
Core Shape
Punnu<T> is the in-process pool. It stores Arc<T> values by
Cacheable::Id, publishes new immutable snapshots after writes, and lets reads
compose explicit predicates over the resident data.
Cacheable tells Sassi how to identify a value. The derive macro can also mark
a monotonic watermark field for delta sync:
For durable or shared L2 backends, give the type an application-owned stable
name with #[cacheable(type_name = "myapp.User")]. Treat that name as part of
the backend schema: it should be unique inside a namespace and reused only for
wire-compatible payloads keyed by the same ids.
BasicPredicate<T> is the shared predicate algebra. It is walkable and
data-layer-projectable, so a fetcher can understand the same constraints that
Sassi can replay in memory. It is not a serde-serializable wire format in
v0.1.0.
MemQ<T> is for local work after data has reached the pool: closure filters,
map, sort, take, unique, group, partition, and fold.
start_periodic_refresh handles simple polling. start_delta_refresh handles
watermark-based subscriptions with per-subscription cursors, single-flight
updates, eviction recovery, and periodic full-refresh policies.
Sassi is the process-level orchestrator for typed pools and cross-type trait
queries registered with #[sassi::trait_impl].
Design Notes For Adopters
A Punnu<T> is a resident union for a type, not a stored result set for one
query. Several subscriptions can feed the same pool. They share the identity
map, but each subscription owns its fetcher, filter, watermark, and recovery
state.
That tradeoff is intentional. Shared identity keeps memory use and cache
coherence manageable, while per-query inclusion stays explicit at read and
refresh boundaries. If a row no longer matches one query, return the updated row
and let predicates stop selecting it. Use tombstones for true deletes from the
identity map. Use RefreshMode::Replace only when the fetcher is authoritative
for the whole resident set.
Sassi also does not infer tenant, auth, pagination, or row-level-security rules
from cached values. Put those boundaries in the type, in the id, in a wrapper
key, or in the fetcher/subscription that owns the query. PunnuConfig::namespace
separates backend keyspaces; it does not isolate the in-process L1 map.
The core crate targets native Rust and wasm32-unknown-unknown. Native
background work uses the runtime-tokio feature. WASM background work uses the
runtime-wasm feature, backed by wasm-bindgen-futures and gloo-timers.
This repository currently verifies the WASM compile path. Full per-test WASM runtime execution is tracked in issue #3. Sassi has no Dioxus-specific API in this repository; a Dioxus app is one possible consumer of the WASM build, not a separately certified integration here.
Status
Sassi's current public beta is 0.1.0-beta.2. The core API,
Redis companion, Bardownski TUI example, benchmark harness, and adopter docs are
in place, with the caution that beta APIs can still move when integration work
finds correctness or ergonomics gaps.
The current beta minimum supported Rust version is 1.95 (set in
[workspace.package].rust-version).
Adopter feedback is welcome. If Sassi looks useful but a workflow is unclear, an API feels awkward, or an integration path is missing, please open a GitHub issue. Early adopter friction is useful signal for the v0.1.x surface.
The current release path is focused on the library crate, the Redis companion,
and the dependency-light bardownski TUI example. A heavier Dioxus/full-stack
Bardownski implementation is planned outside this repository.
Workspace
sassi/ # library crate
sassi-codegen/ # support crate for macro/codegen integrations
sassi-macros/ # support proc-macro crate re-exported by sassi
sassi-cache-redis/ # Redis CacheBackend companion crate
examples/bardownski/ # dependency-light TUI showcase
Most adopters add only sassi to Cargo.toml, plus sassi-cache-redis when
Redis L2 support is needed. sassi-macros and sassi-codegen are published
support crates for Sassi's derive macros and downstream macro integrations; they
are not part of the ordinary application dependency story.
Documentation
- Getting Started
- Concepts
- Query And Refresh Boundaries
- Backends And Runtimes
- Release Readiness
- Bardownski TUI Showcase
- Benchmarks
- Changelog
License
Dual-licensed under MIT or Apache-2.0.