truecalc_workbook/lib.rs
1//! Workbook layer for the [truecalc](https://docs.rs/truecalc-core) spreadsheet
2//! engine: engine-locked workbook, worksheet, and cell value types with a
3//! canonical JSON serialization contract.
4//!
5//! # Quick start
6//!
7//! ```rust
8//! use truecalc_workbook::{Address, CellInput, EngineFlavor, RecalcContext, Value, Workbook, Worksheet};
9//!
10//! // 1. Create a workbook locked to Google Sheets semantics.
11//! let mut wb = Workbook::new(EngineFlavor::Sheets);
12//!
13//! // 2. Add a sheet and write some cells.
14//! wb.add_sheet(Worksheet::new("Budget")).unwrap();
15//! let a1 = Address::from_a1("A1").unwrap();
16//! let a2 = Address::from_a1("A2").unwrap();
17//! let a3 = Address::from_a1("A3").unwrap();
18//! wb.set("Budget", a1, CellInput::Literal(Value::Number(1000.0))).unwrap();
19//! wb.set("Budget", a2, CellInput::Literal(Value::Number(500.0))).unwrap();
20//! wb.set("Budget", a3, CellInput::Formula("=SUM(A1:A2)".to_string())).unwrap();
21//!
22//! // 3. Recalculate to evaluate all formulas.
23//! // timestamp_ms = Unix epoch in ms, tz = IANA timezone id, rng_seed = 0
24//! let ctx = RecalcContext::new(1_780_000_000_000, "Etc/GMT", 0).unwrap();
25//! let _changes = wb.recalc(&ctx);
26//! assert_eq!(wb.get("Budget", a3).unwrap().value(), &Value::Number(1500.0));
27//! ```
28//!
29//! # Core concepts
30//!
31//! - **[`Workbook`]** is a *value object*: `Clone + PartialEq + Hash`, no
32//! hidden state or callbacks. Mutate with [`Workbook::set`] / [`Workbook::clear`]
33//! and then drive recalc with [`Workbook::recalc`] or
34//! [`Workbook::recalc_incremental`].
35//!
36//! - **Engine flavor** ([`EngineFlavor`]) is required at creation
37//! ([`Workbook::new`]) and immutable for the workbook's lifetime. It controls
38//! formula semantics and the date serial system.
39//!
40//! - **[`RecalcContext`]** pins volatile functions (`NOW`, `TODAY`) to a fixed
41//! UTC instant + IANA timezone. Same workbook + same context ⇒ byte-identical
42//! recomputed grid.
43//!
44//! - **[`CellInput`]** is the discriminated input type for [`Workbook::set`]:
45//! `CellInput::Literal(value)` or `CellInput::Formula("=...".to_string())`.
46//! Formula syntax is validated against the locked engine on `set`.
47//!
48//! # Serialization
49//!
50//! [`Workbook::to_json`] / [`Workbook::from_json`] implement the canonical
51//! (RFC 8785 / JCS) serialization boundary — the byte-identical cross-surface
52//! contract used across Rust, WASM, MCP, and REST surfaces.
53//!
54//! # Related crates
55//!
56//! - [`truecalc-core`](https://docs.rs/truecalc-core): the formula parser and
57//! evaluator; the [`Engine`](truecalc_core::Engine) type and all formula
58//! evaluation lives there.
59
60mod address;
61mod canonical;
62mod casefold;
63mod cell;
64mod depgraph;
65mod engine;
66mod error;
67pub mod limits;
68mod mutate;
69mod named_range;
70mod named_ref;
71mod recalc;
72mod spill;
73mod strict_json;
74mod validate;
75mod value;
76mod workbook;
77mod worksheet;
78
79pub use address::Address;
80pub use cell::Cell;
81pub use depgraph::{CellRef, DependencyGraph, Precedent, RangeRef};
82pub use engine::EngineFlavor;
83pub use error::WorkbookError;
84pub use mutate::{CellInput, Resolved};
85pub use named_range::NamedRange;
86pub use recalc::{Change, RecalcContext, CIRCULAR_ERROR};
87pub use spill::{SpillRect, BLOCKED_SPILL_ERROR};
88pub use value::Value;
89pub use workbook::{Workbook, SCHEMA_VERSION};
90pub use worksheet::Worksheet;