Skip to main content

pmcp_workbook_runtime/
excel_error.rs

1//! The shared Excel error-value set — a SMALL value-semantics module owned by
2//! neither the parser AST nor the cell-value boundary, so BOTH can reference it
3//! WITHOUT a module cycle (review finding #9).
4//!
5//! [`ExcelError`] is a value-semantics concept: it is the set of error sentinels
6//! an Excel cell can hold (`#REF!`, `#VALUE!`, …). The parser AST
7//! (`Expr::ErrorLit`) merely *references* it (a literal error parsed from
8//! formula text), and the eval-boundary value type (`CellValue::Error`)
9//! *re-exports* it — neither DEFINES it. Placing it in its own module keeps the
10//! dependency direction acyclic.
11//!
12//! Owned, serde/schemars-clean (the umya-quarantine invariant the whole crate
13//! holds): no `umya`/`quick-xml`/`zip`/`pmcp-code-mode` type appears here. An
14//! error tag carries no `f64`, so `Eq` is sound (unlike `CellValue`).
15
16use serde::{Deserialize, Serialize};
17
18/// The set of Excel error values a cell or a parsed literal can hold.
19///
20/// These are the seven canonical Excel errors. They never enter any kernel
21/// (D-04): an `Error` short-circuits ABOVE the scalar evaluator in the
22/// Excel-semantics layer, so the evaluator stays a pure arithmetic evaluator
23/// with no Excel-error awareness.
24///
25/// `Deserialize` is derived (additive to the original `Serialize`-only shape) so
26/// the BA-owned manifest governed-data table — whose typed value is a
27/// `CellValue` that may be an `Error` — round-trips through serde (Phase 10 Plan
28/// 02, D-03).
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
30pub enum ExcelError {
31    /// `#REF!` — an invalid cell reference.
32    Ref,
33    /// `#VALUE!` — a wrong type of argument or operand.
34    Value,
35    /// `#DIV/0!` — division by zero.
36    DivZero,
37    /// `#N/A` — a value is not available to a function or formula.
38    Na,
39    /// `#NAME?` — an unrecognized name in a formula.
40    Name,
41    /// `#NUM!` — an invalid numeric value in a formula or function.
42    Num,
43    /// `#NULL!` — an empty intersection of two ranges.
44    Null,
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    #[test]
52    fn serializes_each_variant_to_its_tag() {
53        // Serialize-only crate convention (cell_map.rs): assert JSON shape, the
54        // externally-tagged unit variants render as their name strings.
55        assert_eq!(serde_json::to_value(ExcelError::Ref).unwrap(), "Ref");
56        assert_eq!(serde_json::to_value(ExcelError::Value).unwrap(), "Value");
57        assert_eq!(
58            serde_json::to_value(ExcelError::DivZero).unwrap(),
59            "DivZero"
60        );
61        assert_eq!(serde_json::to_value(ExcelError::Na).unwrap(), "Na");
62        assert_eq!(serde_json::to_value(ExcelError::Name).unwrap(), "Name");
63        assert_eq!(serde_json::to_value(ExcelError::Num).unwrap(), "Num");
64        assert_eq!(serde_json::to_value(ExcelError::Null).unwrap(), "Null");
65    }
66}