1use std::cmp::min;
2use std::fmt;
3use std::fmt::Display;
4use std::iter::Sum;
5use std::ops::{Add, BitAnd, Sub};
6
7#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
38pub struct Interval<T> {
39 pub start: T,
40 pub stop: T,
41}
42
43impl<T> Display for &Interval<T>
44where
45 T: Display,
46{
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 write!(f, "[{}, {}]", self.start, self.stop)
49 }
50}
51
52#[derive(Debug)]
74pub struct IntervalCollection<T> {
75 pub elts: Vec<Interval<T>>,
76}
77
78impl<T> Display for &IntervalCollection<T>
79where
80 T: Display,
81{
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 write!(f, "[")?;
84 for (i, elt) in self.elts.iter().enumerate() {
85 if i > 0 {
86 write!(f, ", ")?;
87 }
88 write!(f, "{elt}")?;
89 }
90 write!(f, "]")
91 }
92}
93
94impl<T> Add for &Interval<T>
95where
96 T: Ord + Copy,
97{
98 type Output = IntervalCollection<T>;
99 fn add(self, other: &Interval<T>) -> IntervalCollection<T> {
100 let left = IntervalCollection { elts: vec![*self] };
101 let right = IntervalCollection { elts: vec![*other] };
102 &left + &right
103 }
104}
105
106impl<T> Add for Interval<T>
107where
108 T: Ord + Copy,
109{
110 type Output = IntervalCollection<T>;
111 fn add(self, other: Interval<T>) -> IntervalCollection<T> {
112 let left = IntervalCollection { elts: vec![self] };
113 let right = IntervalCollection { elts: vec![other] };
114 &left + &right
115 }
116}
117
118impl<T> Add<IntervalCollection<T>> for &Interval<T>
119where
120 T: Ord + Copy,
121{
122 type Output = IntervalCollection<T>;
123 fn add(self, other: IntervalCollection<T>) -> IntervalCollection<T> {
124 let left = IntervalCollection { elts: vec![*self] };
125 &left + &other
126 }
127}
128
129impl<T> Add<&IntervalCollection<T>> for &Interval<T>
130where
131 T: Ord + Copy,
132{
133 type Output = IntervalCollection<T>;
134 fn add(self, other: &IntervalCollection<T>) -> IntervalCollection<T> {
135 let left = IntervalCollection { elts: vec![*self] };
136 &left + other
137 }
138}
139
140impl<T> Add<&Interval<T>> for &IntervalCollection<T>
141where
142 T: Ord + Copy,
143{
144 type Output = IntervalCollection<T>;
145 fn add(self, other: &Interval<T>) -> IntervalCollection<T> {
146 let right = IntervalCollection { elts: vec![*other] };
147 self + &right
148 }
149}
150
151impl<T> Add<Interval<T>> for IntervalCollection<T>
152where
153 T: Ord + Copy,
154{
155 type Output = IntervalCollection<T>;
156 fn add(self, other: Interval<T>) -> IntervalCollection<T> {
157 let right = IntervalCollection { elts: vec![other] };
158 self + right
159 }
160}
161
162impl<T> Add<&Interval<T>> for IntervalCollection<T>
163where
164 T: Ord + Copy,
165{
166 type Output = IntervalCollection<T>;
167 fn add(self, other: &Interval<T>) -> IntervalCollection<T> {
168 let right = IntervalCollection { elts: vec![*other] };
169 self + right
170 }
171}
172
173impl<T> Add for &IntervalCollection<T>
174where
175 T: Ord + Copy,
176{
177 type Output = IntervalCollection<T>;
178 fn add(self, other: &IntervalCollection<T>) -> IntervalCollection<T> {
179 let mut elts = Vec::new();
180 let mut start = min(&self.elts[0], &other.elts[0]);
181
182 loop {
183 let swiping_line = start.start;
184 let mut horizon = start.stop;
185
186 horizon = self
187 .elts
188 .iter()
189 .chain(other.elts.iter())
190 .filter(|elt| swiping_line <= elt.start && elt.start <= horizon)
191 .map(|elt| elt.stop)
192 .max()
193 .expect("Unexpected error");
194
195 loop {
196 match self
197 .elts
198 .iter()
199 .chain(other.elts.iter())
200 .filter(|elt| elt.start <= horizon && horizon < elt.stop)
201 .map(|elt| elt.stop)
202 .max()
203 {
204 None => break,
205 Some(x) => horizon = x,
206 }
207 }
208 elts.push(Interval {
209 start: swiping_line,
210 stop: horizon,
211 });
212 match self
213 .elts
214 .iter()
215 .chain(other.elts.iter())
216 .filter(|elt| elt.start > horizon)
217 .min()
218 {
219 None => break,
220 Some(x) => start = x,
221 }
222 }
223
224 IntervalCollection { elts }
225 }
226}
227
228impl<T> Add for IntervalCollection<T>
229where
230 T: Ord + Copy,
231{
232 type Output = IntervalCollection<T>;
233 fn add(self, other: IntervalCollection<T>) -> IntervalCollection<T> {
234 &self + &other
235 }
236}
237impl<T, Delta> Sub for Interval<T>
238where
239 T: Sub<T, Output = Delta> + Add<Delta, Output = T> + Copy + PartialOrd,
240 Delta: Copy,
241{
242 type Output = IntervalCollection<T>;
243 fn sub(self, other: Interval<T>) -> IntervalCollection<T> {
244 let mut elts = Vec::new();
245 if self.overlap(&other) {
246 if other.start > self.start {
247 elts.push(Interval {
248 start: self.start,
249 stop: other.start,
250 })
251 }
252 if other.stop < self.stop {
253 elts.push(Interval {
254 start: other.stop,
255 stop: self.stop,
256 })
257 }
258 } else {
259 elts.push(self)
260 }
261 IntervalCollection { elts }
262 }
263}
264
265impl<T, Delta> Sub<Interval<T>> for IntervalCollection<T>
266where
267 T: Sub<T, Output = Delta> + Add<Delta, Output = T> + Copy + PartialOrd,
268 Delta: Copy,
269{
270 type Output = IntervalCollection<T>;
271 fn sub(self, other: Interval<T>) -> IntervalCollection<T> {
272 let mut elts = Vec::new();
273 for elt in self.elts {
274 if elt.overlap(&other) {
275 if other.start > elt.start {
276 elts.push(Interval {
277 start: elt.start,
278 stop: other.start,
279 })
280 }
281 if other.stop < elt.stop {
282 elts.push(Interval {
283 start: other.stop,
284 stop: elt.stop,
285 })
286 }
287 } else {
288 elts.push(elt)
289 }
290 }
291 IntervalCollection { elts }
292 }
293}
294
295impl<T, Delta> Sub for IntervalCollection<T>
296where
297 T: Sub<T, Output = Delta> + Add<Delta, Output = T> + Copy + PartialOrd,
298 Delta: Copy,
299{
300 type Output = IntervalCollection<T>;
301 fn sub(self, other: IntervalCollection<T>) -> IntervalCollection<T> {
302 let mut res = self;
303 for elt in other.elts {
304 res = res - elt;
305 }
306 res
307 }
308}
309
310impl<T> BitAnd for &Interval<T>
312where
313 T: Copy + Clone + PartialEq + PartialOrd,
314{
315 type Output = Option<Interval<T>>;
316 fn bitand(self, other: &Interval<T>) -> Option<Interval<T>> {
317 match self.overlap(other) {
318 true => Some(Interval {
319 start: match self.start > other.start {
320 true => self.start,
321 false => other.start,
322 },
323 stop: match self.stop < other.stop {
324 true => self.stop,
325 false => other.stop,
326 },
327 }),
328 false => None,
329 }
330 }
331}
332impl<T> BitAnd<&IntervalCollection<T>> for &Interval<T>
333where
334 T: Copy + Clone + PartialEq + PartialOrd,
335{
336 type Output = IntervalCollection<T>;
337 fn bitand(self, other: &IntervalCollection<T>) -> IntervalCollection<T> {
338 let mut elts = Vec::<Interval<T>>::with_capacity(other.elts.len());
339 for interval in &other.elts {
340 match self & interval {
341 None => (),
342 Some(i) => elts.push(i),
343 }
344 }
345 IntervalCollection { elts }
346 }
347}
348
349impl<T> BitAnd<&Interval<T>> for &IntervalCollection<T>
350where
351 T: Copy + Clone + PartialEq + PartialOrd,
352{
353 type Output = IntervalCollection<T>;
354 fn bitand(self, other: &Interval<T>) -> IntervalCollection<T> {
355 other & self
356 }
357}
358
359impl<T> BitAnd for &IntervalCollection<T>
360where
361 T: Copy + Clone + PartialEq + PartialOrd,
362{
363 type Output = IntervalCollection<T>;
364 fn bitand(self, other: &IntervalCollection<T>) -> IntervalCollection<T> {
365 let mut elts = Vec::<Interval<T>>::with_capacity(self.elts.len());
366 for interval in &other.elts {
367 let r = self & interval;
368 elts.extend(r.elts)
369 }
370 IntervalCollection { elts }
371 }
372}
373
374impl<T, Delta> Interval<T>
375where
376 T: Sub<T, Output = Delta> + Add<Delta, Output = T> + Copy,
377 Delta: Copy,
378{
379 pub fn duration(self) -> Delta {
380 self.stop - self.start
381 }
382 pub fn shift(&self, delta: Delta) -> Interval<T> {
383 Interval {
384 start: self.start + delta,
385 stop: self.stop + delta,
386 }
387 }
388}
389
390impl<T> Interval<T>
391where
392 T: PartialOrd,
393{
394 pub fn overlap(&self, other: &Interval<T>) -> bool {
395 self.start < other.stop && self.stop > other.start
396 }
397}
398
399impl<T, Delta> IntervalCollection<T>
400where
401 T: Sub<T, Output = Delta> + Add<Delta, Output = T> + Copy + PartialOrd,
402 Delta: Copy + Sum,
403{
404 pub fn total_duration(&self) -> Delta {
405 self.elts.iter().map(|elt| elt.duration()).sum()
406 }
407}
408
409#[cfg(test)]
410mod tests {
411
412 use super::Interval;
413 use jiff::{Timestamp, ToSpan};
414
415 static I1: Interval<i32> = Interval { start: 0, stop: 1 };
416 static I2: Interval<i32> = Interval { start: 1, stop: 2 };
417 static I3: Interval<i32> = Interval { start: 2, stop: 3 };
418 static I4: Interval<i32> = Interval { start: 3, stop: 4 };
419 static I5: Interval<i32> = Interval { start: 4, stop: 5 };
420
421 #[test]
422 fn interval_i32() {
423 assert_eq!(I1.duration(), 1);
424 let shifted = I1.shift(1);
425 assert_eq!(shifted.duration(), 1);
426 assert_ne!(shifted, I1);
427 assert_eq!(shifted, I2);
428 assert_eq!(format!("{:?}", &shifted), "Interval { start: 1, stop: 2 }");
429 assert_eq!(format!("{:}", &shifted), "[1, 2]");
430 }
431
432 #[test]
433 fn interval_dt() {
434 let i_dt: Interval<Timestamp> = Interval {
435 start: "2024-01-20T12:00:00Z".parse().expect("error date"),
436 stop: "2024-01-20T13:00:00Z".parse().expect("error date"),
437 };
438 assert_eq!(i_dt.duration().compare(1.hour()).unwrap(), std::cmp::Ordering::Equal);
439 assert_eq!(
440 i_dt.shift(5.hour()).duration().compare(1.hour()).unwrap(),
441 std::cmp::Ordering::Equal
442 );
443 }
444 #[test]
445 fn intervals_consistent() {
446 assert_eq!(
447 format!("{:?}", I1 + I2),
448 "IntervalCollection { elts: [Interval { start: 0, stop: 2 }] }"
449 );
450 assert_eq!(format!("{:}", &(I1 + I2)), "[[0, 2]]");
451 assert_eq!(format!("{:}", &(I1 + I3)), "[[0, 1], [2, 3]]");
452 assert_eq!(format!("{:}", &(I2 + I4)), "[[1, 2], [3, 4]]");
453 let s1 = (I1 + I3) + (I2 + I4);
454 assert_eq!(format!("{:}", &s1), "[[0, 4]]");
455 let s2 = (I1 + I3) + (I4 + I5);
456 assert_eq!(format!("{:}", &s2), "[[0, 1], [2, 5]]");
457 let s3 = I1 + I3 + I4 + I5;
458 assert_eq!(format!("{:}", &s3), "[[0, 1], [2, 5]]");
459
460 let i1: Interval<Timestamp> = Interval {
461 start: "2024-01-20T12:00:00Z".parse().expect("error date"),
462 stop: "2024-01-20T13:00:00Z".parse().expect("error date"),
463 };
464 let i2 = Interval {
465 start: "2024-01-20T13:00:00Z".parse().expect("error date"),
466 stop: "2024-01-20T14:00:00Z".parse().expect("error date"),
467 };
468 assert_eq!(
469 format!("{:}", &(i1 + i2)),
470 "[[2024-01-20T12:00:00Z, 2024-01-20T14:00:00Z]]"
471 );
472 }
473
474 #[test]
475 fn intervals_sub() {
476 assert_eq!(format!("{:}", &(I1 - I2)), "[[0, 1]]");
477 assert_eq!(format!("{:}", &(Interval { start: 0, stop: 2 } - I2)), "[[0, 1]]");
478 assert_eq!(format!("{:}", &((I1 + I2 + I3) - I2)), "[[0, 1], [2, 3]]");
479 assert_eq!(format!("{:}", &((I1 + I2) - (I3 + I2))), "[[0, 1]]");
480 assert_eq!(
481 format!("{:}", &(((I1 + I2) + (I2 + I3) + I5) - (I2 + I3))),
482 "[[0, 1], [4, 5]]"
483 );
484 }
485}