9 unstable releases (3 breaking)
| new 0.4.0 | Mar 14, 2026 |
|---|---|
| 0.3.0 | Mar 11, 2026 |
| 0.2.0 | Feb 26, 2026 |
| 0.1.1 | Feb 22, 2026 |
#558 in Data structures
218 downloads per month
Used in 15 crates
(13 directly)
200KB
4.5K
SLoC
Typed state + JSON patch library for deterministic immutable state management.
tirea-state provides typed access to JSON state with automatic patch collection,
enabling deterministic state transitions and full replay capability.
Core Concepts
- State: Trait for types that can create typed state references
- StateRef: Generated typed accessor for reading and writing state
- PatchSink: Automatic operation collector (transparent to developers)
- StateContext: Provides typed state access with automatic patch collection
- StateManager: Manages immutable state with patch history and replay
- Patch: A serializable record of operations to apply to state
Deterministic State Transitions
State' = apply_patch(State, Patch)
- Same
(State, Patch)always produces the sameState' apply_patchis a pure function that never mutates its input- Full history enables replay to any point in time
Quick Start
use tirea_state::{apply_patch, Patch, Op, path};
use serde_json::json;
// Create initial state
let state = json!({"count": 0, "name": "counter"});
// Build a patch
let patch = Patch::new()
.with_op(Op::set(path!("count"), json!(10)))
.with_op(Op::set(path!("updated"), json!(true)));
// Apply patch (pure function)
let new_state = apply_patch(&state, &patch).unwrap();
assert_eq!(new_state["count"], 10);
assert_eq!(new_state["updated"], true);
assert_eq!(state["count"], 0); // Original unchanged
Using Typed State (with derive macro)
For type-safe access with automatic patch collection:
use tirea_state::{StateContext, State};
use tirea_state_derive::State;
use serde::{Serialize, Deserialize};
use serde_json::json;
#[derive(Debug, Clone, Serialize, Deserialize, State)]
struct Counter {
value: i64,
label: String,
}
// In a tool implementation:
async fn execute(&self, ctx: &StateContext<'_>) -> Result<()> {
let counter = ctx.state::<Counter>("counters.main");
// Read
let current = counter.value()?;
// Write (automatically collected)
counter.set_value(current + 1);
counter.set_label("Updated");
Ok(())
}
// Framework calls ctx.take_patch() after execution
Using JsonWriter
For dynamic JSON manipulation without typed structs:
use tirea_state::{JsonWriter, path};
use serde_json::json;
let mut w = JsonWriter::new();
w.set(path!("user", "name"), json!("Alice"));
w.append(path!("user", "roles"), json!("admin"));
w.increment(path!("user", "login_count"), 1i64);
let patch = w.build();
Dependencies
~2.3–4MB
~66K SLoC