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}