Skip to main content

pmcp_workbook_runtime/sheet_ir/
value.rs

1//! The eval-boundary cell value (D-04): [`CellValue`].
2//!
3//! This is the value type that crosses into — and short-circuits ABOVE — the
4//! pure-Rust scalar evaluator. Only `Number`/`Text`/`Bool`/`Empty` lower to a
5//! `JsonValue` and enter the evaluator; [`CellValue::Error`] NEVER lowers — the
6//! Excel-semantics layer short-circuits error propagation above the evaluator,
7//! keeping it a pure arithmetic evaluator with no Excel-error awareness (D-04).
8//!
9//! [`ExcelError`] is RE-EXPORTED from [`crate::excel_error`] (the shared
10//! value-semantics module) — it is NOT redefined here.
11//!
12//! Derive note: `CellValue` derives `PartialEq` but NOT `Eq`, because
13//! [`CellValue::Number`] carries an `f64`.
14//!
15//! `Deserialize` is derived (additive to the original `Serialize`-only shape) so
16//! the BA-owned manifest governed-data table that carries a typed `CellValue`
17//! constant round-trips through serde (Phase 10 Plan 02, D-03).
18
19use serde::{Deserialize, Serialize};
20
21pub use crate::excel_error::ExcelError;
22
23/// An owned cell value at the eval boundary (D-04).
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
25pub enum CellValue {
26    /// A numeric value (full precision retained; the evaluator sees a JSON number).
27    Number(f64),
28    /// A text value.
29    Text(String),
30    /// A boolean value.
31    Bool(bool),
32    /// An empty cell (lowers to `0` for the evaluator — the empty-cell-as-0 rule).
33    Empty,
34    /// An Excel error value — NEVER lowers into the evaluator; the semantics
35    /// layer short-circuits propagation above it (D-04).
36    Error(ExcelError),
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    #[test]
44    fn number_serializes_to_its_value() {
45        assert_eq!(
46            serde_json::to_value(CellValue::Number(238.728)).unwrap()["Number"],
47            238.728
48        );
49    }
50
51    #[test]
52    fn text_serializes() {
53        assert_eq!(
54            serde_json::to_value(CellValue::Text("hi".to_string())).unwrap()["Text"],
55            "hi"
56        );
57    }
58
59    #[test]
60    fn bool_serializes() {
61        assert_eq!(
62            serde_json::to_value(CellValue::Bool(true)).unwrap()["Bool"],
63            true
64        );
65    }
66
67    #[test]
68    fn empty_serializes_to_tag() {
69        assert_eq!(serde_json::to_value(CellValue::Empty).unwrap(), "Empty");
70    }
71
72    #[test]
73    fn error_serializes_re_exported_excel_error() {
74        let v = serde_json::to_value(CellValue::Error(ExcelError::DivZero)).unwrap();
75        assert_eq!(v["Error"], "DivZero");
76    }
77}