lemma/evaluation/
operations.rs1use crate::planning::semantics::{
4 ArithmeticComputation, ComparisonComputation, FactPath, LiteralValue, LogicalComputation,
5 MathematicalComputation, RulePath,
6};
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, PartialEq, Serialize)]
11#[serde(rename_all = "snake_case")]
12pub enum OperationResult {
13 Value(Box<LiteralValue>),
15 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#[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#[derive(Debug, Clone, Serialize)]
45pub struct OperationRecord {
46 #[serde(flatten)]
47 pub kind: OperationKind,
48}
49
50#[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 },
67 RuleBranchEvaluated {
68 #[serde(skip_serializing_if = "Option::is_none")]
69 index: Option<usize>,
70 matched: bool,
71 #[serde(skip_serializing_if = "Option::is_none", default)]
72 result_value: Option<OperationResult>,
73 },
74}
75
76#[cfg(test)]
77mod computation_kind_serde_tests {
78 use super::ComputationKind;
79 use crate::parsing::ast::{
80 ArithmeticComputation, ComparisonComputation, MathematicalComputation,
81 };
82 use crate::planning::semantics::LogicalComputation;
83
84 #[test]
85 fn computation_kind_arithmetic_round_trip() {
86 let k = ComputationKind::Arithmetic(ArithmeticComputation::Add);
87 let json = serde_json::to_string(&k).expect("serialize");
88 assert!(json.contains("\"type\"") && json.contains("\"computation\""));
89 let back: ComputationKind = serde_json::from_str(&json).expect("deserialize");
90 assert_eq!(back, k);
91 }
92
93 #[test]
94 fn computation_kind_comparison_round_trip() {
95 let k = ComputationKind::Comparison(ComparisonComputation::GreaterThan);
96 let json = serde_json::to_string(&k).expect("serialize");
97 let back: ComputationKind = serde_json::from_str(&json).expect("deserialize");
98 assert_eq!(back, k);
99 }
100
101 #[test]
102 fn computation_kind_logical_round_trip() {
103 let k = ComputationKind::Logical(LogicalComputation::And);
104 let json = serde_json::to_string(&k).expect("serialize");
105 let back: ComputationKind = serde_json::from_str(&json).expect("deserialize");
106 assert_eq!(back, k);
107 }
108
109 #[test]
110 fn computation_kind_mathematical_round_trip() {
111 let k = ComputationKind::Mathematical(MathematicalComputation::Sqrt);
112 let json = serde_json::to_string(&k).expect("serialize");
113 let back: ComputationKind = serde_json::from_str(&json).expect("deserialize");
114 assert_eq!(back, k);
115 }
116}