tirea-state 0.1.0

Typed view + JSON patch library for deterministic immutable state management
Documentation

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 same State'
  • apply_patch is 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();