opening_hours_syntax/rules/
mod.rs1pub mod day;
2pub mod time;
3
4use alloc::sync::Arc;
5use alloc::vec::Vec;
6use core::fmt::Display;
7
8use crate::normalize::frame::Bounded;
9use crate::normalize::paving::{Paving, Paving5D, UnpackFromBack};
10use crate::normalize::{canonical_to_seq, ruleseq_to_selector};
11use crate::sorted_vec::UniqueSortedVec;
12
13#[derive(Clone, Debug, Hash, PartialEq, Eq)]
16pub struct OpeningHoursExpression {
17 pub rules: Vec<RuleSequence>,
18}
19
20impl OpeningHoursExpression {
21 pub fn is_constant(&self) -> bool {
35 let Some(kind) = self.rules.last().map(|rs| rs.kind) else {
36 return true;
37 };
38
39 let search_tail_full = self.rules.iter().rev().find(|rs| {
41 rs.day_selector.is_empty() || !rs.time_selector.is_00_24() || rs.kind != kind
42 });
43
44 let Some(tail) = search_tail_full else {
45 return kind == RuleKind::Closed;
46 };
47
48 tail.kind == kind && tail.is_constant()
49 }
50
51 pub fn normalize(self) -> Self {
59 let mut rules_queue = self.rules.into_iter().peekable();
60 let mut paving = Paving5D::default();
61
62 while let Some(rule) = rules_queue.peek() {
63 if rule.operator == RuleOperator::Fallback {
64 break;
65 }
66
67 let Some(selector) = ruleseq_to_selector(rule) else {
68 break;
69 };
70
71 let rule = rules_queue.next().unwrap();
72
73 if rule.operator == RuleOperator::Normal && rule.kind != RuleKind::Closed {
76 let mut full_day_selector = selector.clone();
77 full_day_selector.substitute_back([Bounded::bounds()]);
78 paving.set(&full_day_selector, &Default::default());
79 }
80
81 paving.set(&selector, &(rule.kind, rule.comments));
82 }
83
84 Self {
85 rules: canonical_to_seq(paving).chain(rules_queue).collect(),
86 }
87 }
88}
89
90impl Display for OpeningHoursExpression {
91 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
92 let Some(first) = self.rules.first() else {
93 return write!(f, "closed");
94 };
95
96 write!(f, "{first}")?;
97
98 for rule in &self.rules[1..] {
99 let separator = match rule.operator {
100 RuleOperator::Normal => "; ",
101 RuleOperator::Additional => ", ",
102 RuleOperator::Fallback => " || ",
103 };
104
105 write!(f, "{separator}")?;
106
107 rule.display(f, rule.operator == RuleOperator::Additional)?;
112 }
113
114 Ok(())
115 }
116}
117
118#[derive(Clone, Debug, Hash, PartialEq, Eq)]
121pub struct RuleSequence {
122 pub day_selector: day::DaySelector,
123 pub time_selector: time::TimeSelector,
124 pub kind: RuleKind,
125 pub operator: RuleOperator,
126 pub comments: UniqueSortedVec<Arc<str>>,
127}
128
129impl RuleSequence {
130 pub fn is_constant(&self) -> bool {
133 self.day_selector.is_empty() && self.time_selector.is_00_24()
134 }
135
136 pub(crate) fn display(
141 &self,
142 f: &mut core::fmt::Formatter<'_>,
143 force_day_selector: bool,
144 ) -> core::fmt::Result {
145 let mut is_empty;
146
147 if self.is_constant() {
148 is_empty = false;
149 write!(f, "24/7")?;
150 } else {
151 self.day_selector.display(f, force_day_selector)?;
152 is_empty = !force_day_selector && self.day_selector.is_empty();
153
154 if !self.time_selector.is_00_24() {
155 if !is_empty {
156 write!(f, " ")?;
157 }
158
159 is_empty = is_empty && self.time_selector.is_00_24();
160 write!(f, "{}", self.time_selector)?;
161 }
162 }
163
164 if self.kind != RuleKind::Open {
165 if !is_empty {
166 write!(f, " ")?;
167 }
168
169 is_empty = false;
170 write!(f, "{}", self.kind)?;
171 }
172
173 if !self.comments.is_empty() {
174 if !is_empty {
175 write!(f, " ")?;
176 }
177
178 write!(f, "\"{}\"", self.comments.join(", "))?;
179 }
180
181 Ok(())
182 }
183}
184
185impl Display for RuleSequence {
186 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
187 self.display(f, false)
188 }
189}
190
191#[derive(Copy, Clone, Debug, Default, Hash, Eq, Ord, PartialEq, PartialOrd)]
194pub enum RuleKind {
195 Open,
196 #[default]
197 Closed,
198 Unknown,
199}
200
201impl RuleKind {
202 pub const fn as_str(self) -> &'static str {
203 match self {
204 Self::Open => "open",
205 Self::Closed => "closed",
206 Self::Unknown => "unknown",
207 }
208 }
209}
210
211impl Display for RuleKind {
212 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
213 write!(f, "{}", self.as_str())
214 }
215}
216
217#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
220pub enum RuleOperator {
221 Normal,
222 Additional,
223 Fallback,
224}