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, RangeBound,
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    RangeBound {
166        bound: RangeBound,
167        operand: Box<ShowExpression>,
168    },
169    IsVeto {
170        operand: Box<ShowExpression>,
171    },
172    SpecMember {
173        base: String,
174        member: String,
175    },
176}
177
178impl From<&DomainShowExpression> for ShowExpression {
179    fn from(expression: &DomainShowExpression) -> Self {
180        match expression {
181            DomainShowExpression::Literal(typed) => {
182                let domain_value = type_scoped_result_value_from_literal(
183                    &typed.to_literal(),
184                    typed.lemma_type.as_ref(),
185                )
186                .unwrap_or_else(|failure| {
187                    panic!(
188                        "BUG: show branch literal failed type_scoped_result_value_from_literal: {}",
189                        crate::result_value::rule_result_value_failure_message(failure)
190                    )
191                });
192                Self::Literal {
193                    value: Box::new(RuleResultValue::from(&domain_value)),
194                }
195            }
196            DomainShowExpression::Data { name } => Self::Data { name: name.clone() },
197            DomainShowExpression::Rule { name } => Self::Rule { name: name.clone() },
198            DomainShowExpression::And { left, right } => Self::And {
199                left: Box::new(ShowExpression::from(left.as_ref())),
200                right: Box::new(ShowExpression::from(right.as_ref())),
201            },
202            DomainShowExpression::Not { operand } => Self::Not {
203                operand: Box::new(ShowExpression::from(operand.as_ref())),
204            },
205            DomainShowExpression::Arithmetic { op, left, right } => Self::Arithmetic {
206                op: op.clone(),
207                left: Box::new(ShowExpression::from(left.as_ref())),
208                right: Box::new(ShowExpression::from(right.as_ref())),
209            },
210            DomainShowExpression::Comparison { op, left, right } => Self::Comparison {
211                op: op.clone(),
212                left: Box::new(ShowExpression::from(left.as_ref())),
213                right: Box::new(ShowExpression::from(right.as_ref())),
214            },
215            DomainShowExpression::UnitConversion { operand, target } => Self::UnitConversion {
216                operand: Box::new(ShowExpression::from(operand.as_ref())),
217                target: ShowConversionTarget::from(target),
218            },
219            DomainShowExpression::Math { op, operand } => Self::Math {
220                op: op.clone(),
221                operand: Box::new(ShowExpression::from(operand.as_ref())),
222            },
223            DomainShowExpression::Veto { message } => Self::Veto {
224                message: message.clone(),
225            },
226            DomainShowExpression::Now => Self::Now,
227            DomainShowExpression::DateRelative { kind, operand } => Self::DateRelative {
228                kind: *kind,
229                operand: Box::new(ShowExpression::from(operand.as_ref())),
230            },
231            DomainShowExpression::DateCalendar {
232                kind,
233                unit,
234                operand,
235            } => Self::DateCalendar {
236                kind: *kind,
237                unit: *unit,
238                operand: Box::new(ShowExpression::from(operand.as_ref())),
239            },
240            DomainShowExpression::RangeLiteral { from, to } => Self::RangeLiteral {
241                from: Box::new(ShowExpression::from(from.as_ref())),
242                to: Box::new(ShowExpression::from(to.as_ref())),
243            },
244            DomainShowExpression::PastFutureRange { kind, operand } => Self::PastFutureRange {
245                kind: *kind,
246                operand: Box::new(ShowExpression::from(operand.as_ref())),
247            },
248            DomainShowExpression::RangeContainment { value, range } => Self::RangeContainment {
249                value: Box::new(ShowExpression::from(value.as_ref())),
250                range: Box::new(ShowExpression::from(range.as_ref())),
251            },
252            DomainShowExpression::RangeBound { bound, operand } => Self::RangeBound {
253                bound: *bound,
254                operand: Box::new(ShowExpression::from(operand.as_ref())),
255            },
256            DomainShowExpression::IsVeto { operand } => Self::IsVeto {
257                operand: Box::new(ShowExpression::from(operand.as_ref())),
258            },
259            DomainShowExpression::SpecMember { base, member } => Self::SpecMember {
260                base: base.clone(),
261                member: member.clone(),
262            },
263        }
264    }
265}
266
267#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
268pub struct ShowBranch {
269    #[serde(skip_serializing_if = "Option::is_none", default)]
270    pub condition: Option<ShowExpression>,
271    pub result: ShowExpression,
272}
273
274impl From<&DomainShowBranch> for ShowBranch {
275    fn from(branch: &DomainShowBranch) -> Self {
276        Self {
277            condition: branch.condition.as_ref().map(ShowExpression::from),
278            result: ShowExpression::from(&branch.result),
279        }
280    }
281}
282
283#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
284pub struct ShowRule {
285    #[serde(rename = "type")]
286    pub lemma_type: LemmaType,
287    pub path: Vec<PathSegment>,
288    pub branches: Vec<ShowBranch>,
289    pub depends_on_rules: Vec<String>,
290}
291
292impl From<&DomainShowRule> for ShowRule {
293    fn from(rule: &DomainShowRule) -> Self {
294        Self {
295            lemma_type: LemmaType::from(&rule.lemma_type),
296            path: rule.path.iter().map(PathSegment::from).collect(),
297            branches: rule.branches.iter().map(ShowBranch::from).collect(),
298            depends_on_rules: rule.depends_on_rules.clone(),
299        }
300    }
301}
302
303#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
304pub struct Show {
305    #[serde(skip_serializing_if = "Option::is_none", default)]
306    pub repository: Option<String>,
307    pub spec: String,
308    #[serde(skip_serializing_if = "Option::is_none", default)]
309    pub commentary: Option<String>,
310    #[serde(skip_serializing_if = "Option::is_none", default)]
311    pub effective_from: Option<DateTimeValue>,
312    #[serde(skip_serializing_if = "Option::is_none", default)]
313    pub effective_to: Option<DateTimeValue>,
314    #[serde(skip_serializing_if = "Vec::is_empty", default)]
315    pub versions: Vec<ShowVersion>,
316    pub start_line: usize,
317    #[serde(skip_serializing_if = "Option::is_none", default)]
318    pub source_type: Option<SourceType>,
319    pub data: IndexMap<String, ShowData>,
320    pub rules: IndexMap<String, ShowRule>,
321    pub meta: IndexMap<String, Value>,
322}
323
324impl From<&DomainShow> for Show {
325    fn from(show: &DomainShow) -> Self {
326        Self {
327            repository: show.repository.clone(),
328            spec: show.spec.clone(),
329            commentary: show.commentary.clone(),
330            effective_from: show.effective_from.clone(),
331            effective_to: show.effective_to.clone(),
332            versions: show.versions.iter().map(ShowVersion::from).collect(),
333            start_line: show.start_line,
334            source_type: show.source_type.clone(),
335            data: show
336                .data
337                .iter()
338                .map(|(name, data)| (name.clone(), ShowData::from(data)))
339                .collect(),
340            rules: show
341                .rules
342                .iter()
343                .map(|(name, rule)| (name.clone(), ShowRule::from(rule)))
344                .collect(),
345            meta: show.meta.clone(),
346        }
347    }
348}