Skip to main content

lemma/evaluation/
operations.rs

1//! Operation types and result handling for evaluation
2
3use crate::planning::semantics::{
4    ArithmeticComputation, ComparisonComputation, FactPath, LiteralValue, LogicalComputation,
5    MathematicalComputation, RulePath,
6};
7use serde::{Deserialize, Serialize};
8
9/// Result of an operation (evaluating a rule or expression)
10#[derive(Debug, Clone, PartialEq, Serialize)]
11#[serde(rename_all = "snake_case")]
12pub enum OperationResult {
13    /// Operation produced a value (boxed to keep enum small)
14    Value(Box<LiteralValue>),
15    /// Operation was vetoed (valid result, no value)
16    Veto(Option<String>),
17}
18
19impl OperationResult {
20    pub fn vetoed(&self) -> bool {
21        matches!(self, OperationResult::Veto(_))
22    }
23
24    #[must_use]
25    pub fn value(&self) -> Option<&LiteralValue> {
26        match self {
27            OperationResult::Value(v) => Some(v.as_ref()),
28            OperationResult::Veto(_) => None,
29        }
30    }
31}
32
33/// The kind of computation performed
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
35#[serde(tag = "type", content = "computation", rename_all = "snake_case")]
36pub enum ComputationKind {
37    Arithmetic(ArithmeticComputation),
38    Comparison(ComparisonComputation),
39    Logical(LogicalComputation),
40    Mathematical(MathematicalComputation),
41}
42
43/// A record of a single operation during evaluation
44#[derive(Debug, Clone, Serialize)]
45pub struct OperationRecord {
46    #[serde(flatten)]
47    pub kind: OperationKind,
48}
49
50/// The kind of operation performed
51#[derive(Debug, Clone, Serialize)]
52#[serde(tag = "type", rename_all = "snake_case")]
53pub enum OperationKind {
54    FactUsed {
55        fact_ref: FactPath,
56        value: LiteralValue,
57    },
58    RuleUsed {
59        rule_path: RulePath,
60        result: OperationResult,
61    },
62    Computation {
63        kind: ComputationKind,
64        inputs: Vec<LiteralValue>,
65        result: LiteralValue,
66        #[serde(skip_serializing_if = "Option::is_none", default)]
67        expr: Option<String>,
68    },
69    RuleBranchEvaluated {
70        #[serde(skip_serializing_if = "Option::is_none")]
71        index: Option<usize>,
72        matched: bool,
73        #[serde(skip_serializing_if = "Option::is_none", default)]
74        condition_expr: Option<String>,
75        #[serde(skip_serializing_if = "Option::is_none", default)]
76        result_expr: Option<String>,
77        #[serde(skip_serializing_if = "Option::is_none", default)]
78        result_value: Option<OperationResult>,
79    },
80}
81
82#[cfg(test)]
83mod computation_kind_serde_tests {
84    use super::ComputationKind;
85    use crate::parsing::ast::{
86        ArithmeticComputation, ComparisonComputation, MathematicalComputation,
87    };
88    use crate::planning::semantics::LogicalComputation;
89
90    #[test]
91    fn computation_kind_arithmetic_round_trip() {
92        let k = ComputationKind::Arithmetic(ArithmeticComputation::Add);
93        let json = serde_json::to_string(&k).expect("serialize");
94        assert!(json.contains("\"type\"") && json.contains("\"computation\""));
95        let back: ComputationKind = serde_json::from_str(&json).expect("deserialize");
96        assert_eq!(back, k);
97    }
98
99    #[test]
100    fn computation_kind_comparison_round_trip() {
101        let k = ComputationKind::Comparison(ComparisonComputation::GreaterThan);
102        let json = serde_json::to_string(&k).expect("serialize");
103        let back: ComputationKind = serde_json::from_str(&json).expect("deserialize");
104        assert_eq!(back, k);
105    }
106
107    #[test]
108    fn computation_kind_logical_round_trip() {
109        let k = ComputationKind::Logical(LogicalComputation::And);
110        let json = serde_json::to_string(&k).expect("serialize");
111        let back: ComputationKind = serde_json::from_str(&json).expect("deserialize");
112        assert_eq!(back, k);
113    }
114
115    #[test]
116    fn computation_kind_mathematical_round_trip() {
117        let k = ComputationKind::Mathematical(MathematicalComputation::Sqrt);
118        let json = serde_json::to_string(&k).expect("serialize");
119        let back: ComputationKind = serde_json::from_str(&json).expect("deserialize");
120        assert_eq!(back, k);
121    }
122}