tirea_state/lib.rs
1//! Typed state + JSON patch library for deterministic immutable state management.
2//!
3//! `tirea-state` provides typed access to JSON state with automatic patch collection,
4//! enabling deterministic state transitions and full replay capability.
5//!
6//! # Core Concepts
7//!
8//! - **State**: Trait for types that can create typed state references
9//! - **StateRef**: Generated typed accessor for reading and writing state
10//! - **PatchSink**: Automatic operation collector (transparent to developers)
11//! - **StateContext**: Provides typed state access with automatic patch collection
12//! - **StateManager**: Manages immutable state with patch history and replay
13//! - **Patch**: A serializable record of operations to apply to state
14//!
15//! # Deterministic State Transitions
16//!
17//! ```text
18//! State' = apply_patch(State, Patch)
19//! ```
20//!
21//! - Same `(State, Patch)` always produces the same `State'`
22//! - `apply_patch` is a pure function that never mutates its input
23//! - Full history enables replay to any point in time
24//!
25//! # Quick Start
26//!
27//! ```
28//! use tirea_state::{apply_patch, Patch, Op, path};
29//! use serde_json::json;
30//!
31//! // Create initial state
32//! let state = json!({"count": 0, "name": "counter"});
33//!
34//! // Build a patch
35//! let patch = Patch::new()
36//! .with_op(Op::set(path!("count"), json!(10)))
37//! .with_op(Op::set(path!("updated"), json!(true)));
38//!
39//! // Apply patch (pure function)
40//! let new_state = apply_patch(&state, &patch).unwrap();
41//!
42//! assert_eq!(new_state["count"], 10);
43//! assert_eq!(new_state["updated"], true);
44//! assert_eq!(state["count"], 0); // Original unchanged
45//! ```
46//!
47//! # Using Typed State (with derive macro)
48//!
49//! For type-safe access with automatic patch collection:
50//!
51//! ```ignore
52//! use tirea_state::{StateContext, State};
53//! use tirea_state_derive::State;
54//! use serde::{Serialize, Deserialize};
55//! use serde_json::json;
56//!
57//! #[derive(Debug, Clone, Serialize, Deserialize, State)]
58//! struct Counter {
59//! value: i64,
60//! label: String,
61//! }
62//!
63//! // In a tool implementation:
64//! async fn execute(&self, ctx: &StateContext<'_>) -> Result<()> {
65//! let counter = ctx.state::<Counter>("counters.main");
66//!
67//! // Read
68//! let current = counter.value()?;
69//!
70//! // Write (automatically collected)
71//! counter.set_value(current + 1);
72//! counter.set_label("Updated");
73//!
74//! Ok(())
75//! }
76//! // Framework calls ctx.take_patch() after execution
77//! ```
78//!
79//! # Using JsonWriter
80//!
81//! For dynamic JSON manipulation without typed structs:
82//!
83//! ```
84//! use tirea_state::{JsonWriter, path};
85//! use serde_json::json;
86//!
87//! let mut w = JsonWriter::new();
88//! w.set(path!("user", "name"), json!("Alice"));
89//! w.append(path!("user", "roles"), json!("admin"));
90//! w.increment(path!("user", "login_count"), 1i64);
91//!
92//! let patch = w.build();
93//! ```
94
95mod apply;
96mod conflict;
97mod delta_tracked;
98mod doc_cell;
99mod error;
100pub mod lattice;
101mod manager;
102mod op;
103mod patch;
104mod path;
105pub mod runtime;
106mod state;
107mod writer;
108
109// Lattice / CRDT primitives
110pub use lattice::{
111 Flag, GCounter, GSet, Lattice, LatticeMerger, LatticeRegistry, MaxReg, MinReg, ORMap, ORSet,
112};
113
114// Core types
115pub use apply::{
116 apply_patch, apply_patch_with_registry, apply_patches, apply_patches_with_registry, get_at_path,
117};
118pub use conflict::{
119 compute_touched, conflicts_with_registry, detect_conflicts, Conflict, ConflictKind, PatchExt,
120};
121pub use delta_tracked::DeltaTracked;
122pub use doc_cell::DocCell;
123pub use error::{value_type_name, TireaError, TireaResult};
124pub use op::{Number, Op};
125pub use patch::{Patch, TrackedPatch};
126pub use path::{Path, Seg};
127pub use writer::JsonWriter;
128
129// State types
130pub use manager::{ApplyResult, StateError, StateManager};
131pub use runtime::{SealedState, SealedStateError};
132pub use state::{parse_path, PatchSink, State, StateContext, StateExt, StateScope, StateSpec};
133
134// Re-export derive macros when feature is enabled
135#[cfg(feature = "derive")]
136pub use tirea_state_derive::{Lattice, State};
137
138// Re-export serde_json::Value for convenience
139pub use serde_json::Value;