Skip to main content

lemma/api/
show.rs

1//! Show / ShowData / ShowRule / ShowExpression JSON shapes.
2
3use crate::api::types::LemmaType;
4use crate::api::value::RuleResultValue;
5use crate::literals::Value;
6use crate::parsing::ast::{
7    ArithmeticComputation, CalendarPeriodUnit, ComparisonComputation, DateCalendarKind,
8    DateRelativeKind, DateTimeValue, MathematicalComputation, PrimitiveKind,
9};
10use crate::parsing::source::SourceType;
11use crate::planning::execution_plan::{
12    Show as DomainShow, ShowBranch as DomainShowBranch,
13    ShowConversionTarget as DomainConversionTarget, ShowData as DomainShowData,
14    ShowExpression as DomainShowExpression, ShowRule as DomainShowRule,
15    ShowVersion as DomainShowVersion,
16};
17use crate::planning::semantics::PathSegment as DomainPathSegment;
18use crate::result_value::type_scoped_result_value_from_literal;
19use indexmap::IndexMap;
20use serde::{Deserialize, Serialize};
21
22/// One `uses` hop on a Show data or rule path.
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
24pub struct PathSegment {
25    pub uses: String,
26    #[serde(skip_serializing_if = "Option::is_none", default)]
27    pub repository: Option<String>,
28    pub spec: String,
29}
30
31impl From<&DomainPathSegment> for PathSegment {
32    fn from(segment: &DomainPathSegment) -> Self {
33        Self {
34            uses: segment.uses.clone(),
35            repository: segment.repository.clone(),
36            spec: segment.spec.clone(),
37        }
38    }
39}
40
41#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
42pub struct ShowData {
43    #[serde(rename = "type")]
44    pub lemma_type: LemmaType,
45    pub path: Vec<PathSegment>,
46    #[serde(skip_serializing_if = "Option::is_none", default)]
47    pub fill: Option<RuleResultValue>,
48    #[serde(skip_serializing_if = "Option::is_none", default)]
49    pub suggestion: Option<RuleResultValue>,
50    pub needed_by_rules: Vec<String>,
51}
52
53impl From<&DomainShowData> for ShowData {
54    fn from(data: &DomainShowData) -> Self {
55        Self {
56            lemma_type: LemmaType::from(&data.lemma_type),
57            path: data.path.iter().map(PathSegment::from).collect(),
58            fill: data.fill.as_ref().map(RuleResultValue::from),
59            suggestion: data.suggestion.as_ref().map(RuleResultValue::from),
60            needed_by_rules: data.needed_by_rules.clone(),
61        }
62    }
63}
64
65#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
66pub struct ShowVersion {
67    #[serde(skip_serializing_if = "Option::is_none", default)]
68    pub effective_from: Option<DateTimeValue>,
69    #[serde(skip_serializing_if = "Option::is_none", default)]
70    pub effective_to: Option<DateTimeValue>,
71}
72
73impl From<&DomainShowVersion> for ShowVersion {
74    fn from(version: &DomainShowVersion) -> Self {
75        Self {
76            effective_from: version.effective_from.clone(),
77            effective_to: version.effective_to.clone(),
78        }
79    }
80}
81
82#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
83#[serde(rename_all = "snake_case")]
84pub enum ShowConversionTarget {
85    Type(PrimitiveKind),
86    Unit { unit_name: String },
87}
88
89impl From<&DomainConversionTarget> for ShowConversionTarget {
90    fn from(target: &DomainConversionTarget) -> Self {
91        match target {
92            DomainConversionTarget::Type(kind) => Self::Type(*kind),
93            DomainConversionTarget::Unit { unit_name } => Self::Unit {
94                unit_name: unit_name.clone(),
95            },
96        }
97    }
98}
99
100/// Resolved expression on a Show rule branch.
101#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
102#[serde(tag = "type", rename_all = "snake_case")]
103pub enum ShowExpression {
104    Literal {
105        #[serde(flatten)]
106        value: Box<RuleResultValue>,
107    },
108    Data {
109        name: String,
110    },
111    Rule {
112        name: String,
113    },
114    And {
115        left: Box<ShowExpression>,
116        right: Box<ShowExpression>,
117    },
118    Not {
119        operand: Box<ShowExpression>,
120    },
121    Arithmetic {
122        op: ArithmeticComputation,
123        left: Box<ShowExpression>,
124        right: Box<ShowExpression>,
125    },
126    Comparison {
127        op: ComparisonComputation,
128        left: Box<ShowExpression>,
129        right: Box<ShowExpression>,
130    },
131    UnitConversion {
132        operand: Box<ShowExpression>,
133        target: ShowConversionTarget,
134    },
135    Math {
136        op: MathematicalComputation,
137        operand: Box<ShowExpression>,
138    },
139    Veto {
140        #[serde(skip_serializing_if = "Option::is_none", default)]
141        message: Option<String>,
142    },
143    Now,
144    DateRelative {
145        kind: DateRelativeKind,
146        operand: Box<ShowExpression>,
147    },
148    DateCalendar {
149        kind: DateCalendarKind,
150        unit: CalendarPeriodUnit,
151        operand: Box<ShowExpression>,
152    },
153    RangeLiteral {
154        from: Box<ShowExpression>,
155        to: Box<ShowExpression>,
156    },
157    PastFutureRange {
158        kind: DateRelativeKind,
159        operand: Box<ShowExpression>,
160    },
161    RangeContainment {
162        value: Box<ShowExpression>,
163        range: Box<ShowExpression>,
164    },
165    IsVeto {
166        operand: Box<ShowExpression>,
167    },
168}
169
170impl From<&DomainShowExpression> for ShowExpression {
171    fn from(expression: &DomainShowExpression) -> Self {
172        match expression {
173            DomainShowExpression::Literal(typed) => {
174                let domain_value = type_scoped_result_value_from_literal(
175                    &typed.to_literal(),
176                    typed.lemma_type.as_ref(),
177                )
178                .unwrap_or_else(|failure| {
179                    panic!(
180                        "BUG: show branch literal failed type_scoped_result_value_from_literal: {}",
181                        crate::result_value::rule_result_value_failure_message(failure)
182                    )
183                });
184                Self::Literal {
185                    value: Box::new(RuleResultValue::from(&domain_value)),
186                }
187            }
188            DomainShowExpression::Data { name } => Self::Data { name: name.clone() },
189            DomainShowExpression::Rule { name } => Self::Rule { name: name.clone() },
190            DomainShowExpression::And { left, right } => Self::And {
191                left: Box::new(ShowExpression::from(left.as_ref())),
192                right: Box::new(ShowExpression::from(right.as_ref())),
193            },
194            DomainShowExpression::Not { operand } => Self::Not {
195                operand: Box::new(ShowExpression::from(operand.as_ref())),
196            },
197            DomainShowExpression::Arithmetic { op, left, right } => Self::Arithmetic {
198                op: op.clone(),
199                left: Box::new(ShowExpression::from(left.as_ref())),
200                right: Box::new(ShowExpression::from(right.as_ref())),
201            },
202            DomainShowExpression::Comparison { op, left, right } => Self::Comparison {
203                op: op.clone(),
204                left: Box::new(ShowExpression::from(left.as_ref())),
205                right: Box::new(ShowExpression::from(right.as_ref())),
206            },
207            DomainShowExpression::UnitConversion { operand, target } => Self::UnitConversion {
208                operand: Box::new(ShowExpression::from(operand.as_ref())),
209                target: ShowConversionTarget::from(target),
210            },
211            DomainShowExpression::Math { op, operand } => Self::Math {
212                op: op.clone(),
213                operand: Box::new(ShowExpression::from(operand.as_ref())),
214            },
215            DomainShowExpression::Veto { message } => Self::Veto {
216                message: message.clone(),
217            },
218            DomainShowExpression::Now => Self::Now,
219            DomainShowExpression::DateRelative { kind, operand } => Self::DateRelative {
220                kind: *kind,
221                operand: Box::new(ShowExpression::from(operand.as_ref())),
222            },
223            DomainShowExpression::DateCalendar {
224                kind,
225                unit,
226                operand,
227            } => Self::DateCalendar {
228                kind: *kind,
229                unit: *unit,
230                operand: Box::new(ShowExpression::from(operand.as_ref())),
231            },
232            DomainShowExpression::RangeLiteral { from, to } => Self::RangeLiteral {
233                from: Box::new(ShowExpression::from(from.as_ref())),
234                to: Box::new(ShowExpression::from(to.as_ref())),
235            },
236            DomainShowExpression::PastFutureRange { kind, operand } => Self::PastFutureRange {
237                kind: *kind,
238                operand: Box::new(ShowExpression::from(operand.as_ref())),
239            },
240            DomainShowExpression::RangeContainment { value, range } => Self::RangeContainment {
241                value: Box::new(ShowExpression::from(value.as_ref())),
242                range: Box::new(ShowExpression::from(range.as_ref())),
243            },
244            DomainShowExpression::IsVeto { operand } => Self::IsVeto {
245                operand: Box::new(ShowExpression::from(operand.as_ref())),
246            },
247        }
248    }
249}
250
251#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
252pub struct ShowBranch {
253    #[serde(skip_serializing_if = "Option::is_none", default)]
254    pub condition: Option<ShowExpression>,
255    pub result: ShowExpression,
256}
257
258impl From<&DomainShowBranch> for ShowBranch {
259    fn from(branch: &DomainShowBranch) -> Self {
260        Self {
261            condition: branch.condition.as_ref().map(ShowExpression::from),
262            result: ShowExpression::from(&branch.result),
263        }
264    }
265}
266
267#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
268pub struct ShowRule {
269    #[serde(rename = "type")]
270    pub lemma_type: LemmaType,
271    pub path: Vec<PathSegment>,
272    pub branches: Vec<ShowBranch>,
273    pub depends_on_rules: Vec<String>,
274}
275
276impl From<&DomainShowRule> for ShowRule {
277    fn from(rule: &DomainShowRule) -> Self {
278        Self {
279            lemma_type: LemmaType::from(&rule.lemma_type),
280            path: rule.path.iter().map(PathSegment::from).collect(),
281            branches: rule.branches.iter().map(ShowBranch::from).collect(),
282            depends_on_rules: rule.depends_on_rules.clone(),
283        }
284    }
285}
286
287#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
288pub struct Show {
289    #[serde(skip_serializing_if = "Option::is_none", default)]
290    pub repository: Option<String>,
291    pub spec: String,
292    #[serde(skip_serializing_if = "Option::is_none", default)]
293    pub commentary: Option<String>,
294    #[serde(skip_serializing_if = "Option::is_none", default)]
295    pub effective_from: Option<DateTimeValue>,
296    #[serde(skip_serializing_if = "Option::is_none", default)]
297    pub effective_to: Option<DateTimeValue>,
298    #[serde(skip_serializing_if = "Vec::is_empty", default)]
299    pub versions: Vec<ShowVersion>,
300    pub start_line: usize,
301    #[serde(skip_serializing_if = "Option::is_none", default)]
302    pub source_type: Option<SourceType>,
303    pub data: IndexMap<String, ShowData>,
304    pub rules: IndexMap<String, ShowRule>,
305    pub meta: IndexMap<String, Value>,
306}
307
308impl From<&DomainShow> for Show {
309    fn from(show: &DomainShow) -> Self {
310        Self {
311            repository: show.repository.clone(),
312            spec: show.spec.clone(),
313            commentary: show.commentary.clone(),
314            effective_from: show.effective_from.clone(),
315            effective_to: show.effective_to.clone(),
316            versions: show.versions.iter().map(ShowVersion::from).collect(),
317            start_line: show.start_line,
318            source_type: show.source_type.clone(),
319            data: show
320                .data
321                .iter()
322                .map(|(name, data)| (name.clone(), ShowData::from(data)))
323                .collect(),
324            rules: show
325                .rules
326                .iter()
327                .map(|(name, rule)| (name.clone(), ShowRule::from(rule)))
328                .collect(),
329            meta: show.meta.clone(),
330        }
331    }
332}