lemma/planning/
explanation.rs1use crate::parsing::ast::ArithmeticComputation;
18use crate::planning::semantics::{DataPath, RulePath};
19use crate::result_value::RuleResultValue;
20use serde::{Serialize, Serializer};
21
22pub(crate) fn serialize_rule_path_as_name<S>(
23 path: &RulePath,
24 serializer: S,
25) -> Result<S::Ok, S::Error>
26where
27 S: Serializer,
28{
29 serializer.serialize_str(&path.input_key())
30}
31
32pub(crate) fn serialize_data_path_as_name<S>(
33 path: &DataPath,
34 serializer: S,
35) -> Result<S::Ok, S::Error>
36where
37 S: Serializer,
38{
39 serializer.serialize_str(&path.input_key())
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
45#[serde(transparent)]
46pub struct ExplainedRuleId(pub u32);
47
48#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
50pub struct ExplainedRule {
51 pub id: ExplainedRuleId,
52 #[serde(serialize_with = "serialize_rule_path_as_name")]
53 pub name: RulePath,
54 #[serde(flatten)]
55 pub result: RuleResultValue,
56 pub body: String,
57 #[serde(skip_serializing_if = "Vec::is_empty")]
58 pub causes: Vec<Cause>,
59 #[serde(skip_serializing_if = "Vec::is_empty")]
60 pub children: Vec<ExplanationNode>,
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
64#[serde(tag = "type", rename_all = "snake_case")]
65pub enum ExplanationNode {
66 RuleRef {
68 id: ExplainedRuleId,
69 #[serde(serialize_with = "serialize_rule_path_as_name")]
70 name: RulePath,
71 #[serde(flatten)]
72 result: RuleResultValue,
73 },
74 Compose {
75 expression: String,
76 #[serde(skip_serializing_if = "Option::is_none")]
77 operator: Option<ArithmeticComputation>,
78 operands: Vec<ExplanationNode>,
79 },
80 Data {
82 #[serde(serialize_with = "serialize_data_path_as_name")]
83 name: DataPath,
84 #[serde(flatten)]
85 result: RuleResultValue,
86 },
87 DataUnused {
90 #[serde(serialize_with = "serialize_data_path_as_name")]
91 name: DataPath,
92 },
93 Conversion {
94 expression: String,
95 steps: Vec<SerializedConversionTraceStep>,
96 operands: Vec<ExplanationNode>,
97 },
98 Veto {
99 #[serde(skip_serializing_if = "Option::is_none")]
100 message: Option<String>,
101 },
102 Row {
104 number: usize,
105 #[serde(skip_serializing_if = "std::ops::Not::not")]
106 appended: bool,
107 #[serde(skip_serializing_if = "Vec::is_empty")]
108 key: Vec<ExplanationNode>,
109 fields: Vec<ExplanationNode>,
110 },
111 Filter {
113 condition: String,
114 matched: usize,
115 total: usize,
116 #[serde(skip_serializing_if = "Vec::is_empty")]
117 children: Vec<ExplanationNode>,
118 },
119}
120
121#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
122pub struct Cause {
123 pub condition: String,
124 pub value: String,
125 #[serde(skip_serializing_if = "Vec::is_empty")]
126 pub children: Vec<ExplanationNode>,
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
130#[serde(rename_all = "snake_case")]
131pub enum ConversionTraceRole {
132 Outcome,
133 Rule,
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
137pub struct SerializedConversionTraceStep {
138 pub(crate) role: ConversionTraceRole,
139 pub(crate) text: String,
140}