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 ;
use json;
// Create initial state
let state = json!;
// Build a patch
let patch = new
.with_op
.with_op;
// Apply patch (pure function)
let new_state = apply_patch.unwrap;
assert_eq!;
assert_eq!;
assert_eq!; // 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 ;
use json;
let mut w = new;
w.set;
w.append;
w.increment;
let patch = w.build;