opening_hours/
schedule.rs1use std::cmp::{max, min};
2use std::iter::Peekable;
3use std::ops::Range;
4use std::sync::Arc;
5
6use opening_hours_syntax::{ExtendedTime, RuleKind};
7
8#[derive(Clone, Debug, Eq, PartialEq)]
10pub struct TimeRange {
11 pub range: Range<ExtendedTime>,
13 pub kind: RuleKind,
15 pub comment: Arc<str>,
17}
18
19impl TimeRange {
20 pub fn new(range: Range<ExtendedTime>, kind: RuleKind, comment: Arc<str>) -> Self {
22 TimeRange { range, kind, comment }
23 }
24
25 pub fn as_state(&self) -> (RuleKind, &str) {
28 (self.kind, &self.comment)
29 }
30}
31
32#[derive(Clone, Debug, Default, Eq, PartialEq)]
38pub struct Schedule {
39 pub(crate) inner: Vec<TimeRange>,
41}
42
43impl Schedule {
44 pub fn new() -> Self {
52 Self::default()
53 }
54
55 pub fn from_ranges(
79 ranges: impl IntoIterator<Item = Range<ExtendedTime>>,
80 kind: RuleKind,
81 comment: Arc<str>,
82 ) -> Self {
83 let mut inner: Vec<_> = ranges
84 .into_iter()
85 .filter(|range| range.start < range.end)
86 .map(|range| TimeRange { range, kind, comment: comment.clone() })
87 .collect();
88
89 if inner.len() > 1 {
91 inner.sort_unstable_by_key(|rng| rng.range.start);
92 let mut i_kept = 0; for i_next in 1..inner.len() {
95 if inner[i_kept].range.end >= inner[i_next].range.start {
96 inner[i_kept].range.end = inner[i_next].range.end;
97 } else {
98 i_kept += 1;
99 inner.swap(i_kept, i_next);
100 }
101 }
102
103 inner.truncate(i_kept + 1);
104 }
105
106 Self { inner }
107 }
108
109 pub fn is_empty(&self) -> bool {
117 self.inner.is_empty()
118 }
119
120 pub(crate) fn is_always_closed_with_no_comments(&self) -> bool {
122 self.inner
123 .iter()
124 .all(|rg| rg.kind == RuleKind::Closed && rg.comment.is_empty())
125 }
126
127 pub fn filter_closed_ranges(mut self) -> Self {
129 self.inner
130 .retain(|rg| rg.kind != RuleKind::Closed || !rg.comment.is_empty());
131
132 self
133 }
134
135 pub fn addition(self, mut other: Self) -> Self {
137 match other.inner.pop() {
140 None => self,
141 Some(tr) => self.insert(tr).addition(other),
142 }
143 }
144
145 fn insert(self, mut ins_tr: TimeRange) -> Self {
147 let ins_start = ins_tr.range.start;
150 let ins_end = ins_tr.range.end;
151
152 let mut before: Vec<_> = self
153 .inner
154 .iter()
155 .filter(|tr| tr.range.start < ins_end)
156 .cloned()
157 .filter_map(|mut tr| {
158 tr.range.end = min(tr.range.end, ins_tr.range.start);
159
160 if tr.range.start < tr.range.end {
161 Some(tr)
162 } else {
163 None
164 }
165 })
166 .collect();
167
168 let mut after = self
169 .inner
170 .into_iter()
171 .filter(|tr| tr.range.end > ins_start)
172 .filter_map(|mut tr| {
173 tr.range.start = max(tr.range.start, ins_tr.range.end);
174
175 if tr.range.start < tr.range.end {
176 Some(tr)
177 } else {
178 None
179 }
180 })
181 .collect::<Vec<_>>()
182 .into_iter()
183 .peekable();
184
185 while let Some(tr) = before
188 .pop_if(|tr| tr.range.end == ins_tr.range.start && tr.as_state() == ins_tr.as_state())
189 {
190 ins_tr.range.start = tr.range.start;
191 }
192
193 while let Some(tr) = after
194 .next_if(|tr| ins_tr.range.end == tr.range.start && tr.as_state() == ins_tr.as_state())
195 {
196 ins_tr.range.end = tr.range.end;
197 }
198
199 let mut inner = before;
202 inner.push(ins_tr);
203 inner.extend(after);
204 Schedule { inner }
205 }
206}
207
208impl IntoIterator for Schedule {
209 type Item = TimeRange;
210 type IntoIter = IntoIter;
211
212 fn into_iter(self) -> Self::IntoIter {
213 IntoIter::new(self)
214 }
215}
216
217#[derive(Debug)]
219pub struct IntoIter {
220 last_end: ExtendedTime,
221 ranges: Peekable<std::vec::IntoIter<TimeRange>>,
222}
223
224impl IntoIter {
225 const HOLES_STATE: (RuleKind, &str) = (RuleKind::Closed, "");
227
228 fn new(schedule: Schedule) -> Self {
230 Self {
231 last_end: ExtendedTime::MIDNIGHT_00,
232 ranges: schedule.inner.into_iter().peekable(),
233 }
234 }
235
236 fn yielded(&mut self, value: TimeRange) -> Option<TimeRange> {
238 assert!(
239 value.range.start < value.range.end,
240 "infinite loop detected"
241 );
242
243 self.last_end = value.range.end;
244 Some(value)
245 }
246}
247
248impl Iterator for IntoIter {
249 type Item = TimeRange;
250
251 fn next(&mut self) -> Option<Self::Item> {
252 if self.last_end >= ExtendedTime::MIDNIGHT_24 {
253 return None;
255 }
256
257 let mut yielded_range = (self.ranges)
258 .next_if(|tr| tr.range.start == self.last_end)
260 .unwrap_or_else(|| {
262 let start = self.last_end;
263 let end = self.ranges.peek().map(|tr| tr.range.start).unwrap_or(start);
264 TimeRange::new(start..end, Self::HOLES_STATE.0, Default::default())
265 });
266
267 while let Some(next_range) = self.ranges.peek() {
268 if next_range.range.start > yielded_range.range.end {
270 if yielded_range.as_state() == Self::HOLES_STATE {
272 yielded_range.range.end = next_range.range.start;
274 } else {
275 return self.yielded(yielded_range);
278 }
279 }
280
281 let Some(next_range) = (self.ranges)
282 .next_if(|next_range| yielded_range.as_state() == next_range.as_state())
283 else {
284 return self.yielded(yielded_range);
287 };
288
289 yielded_range.range.end = next_range.range.end;
290 }
291
292 if yielded_range.as_state() == Self::HOLES_STATE {
293 yielded_range.range.end = ExtendedTime::MIDNIGHT_24;
295 }
296
297 self.yielded(yielded_range)
298 }
299}
300
301impl std::iter::FusedIterator for IntoIter {}