timekeep_rs/
atomic.rs

1//! A module containing the `AtomicInterval` struct and its implementations.
2//! An atomic interval is a closed or open interval that contains a single value or a range of values.
3//! 
4//! # Examples
5//! ```
6//! use timekeep_rs::{AtomicInterval, Bound};
7//! 
8//! let interval = AtomicInterval::closed(1, 5);
9//! assert_eq!(*interval.left(), Bound::Included(1));
10//! assert_eq!(*interval.right(), Bound::Included(5));
11//! ```
12//!
13use crate::Bound;
14
15/// A struct representing an atomic interval.
16/// An atomic interval is a closed or open interval that contains a single value or a range of values.
17/// 
18/// # Fields
19/// * `left` - The left endpoint of the interval
20/// * `right` - The right endpoint of the interval
21/// 
22/// # Examples
23/// ```
24/// use timekeep_rs::{AtomicInterval, Bound};
25///
26/// let interval = AtomicInterval::closed(1, 5);
27/// assert_eq!(*interval.left(), Bound::Included(1));
28/// assert_eq!(*interval.right(), Bound::Included(5));
29/// ```
30/// 
31#[derive(PartialEq, Debug, Clone)]
32pub struct AtomicInterval<T> {
33    left: Bound<T>,
34    right: Bound<T>,
35}
36
37
38/// Implementation of the `ToString` trait for `AtomicInterval`.
39impl<T: ToString> ToString for AtomicInterval<T> {
40    /// This allows `AtomicInterval` to be converted to a string.
41    /// 
42    /// # Returns
43    /// A string representation of the `AtomicInterval`
44    fn to_string(&self) -> String {
45        match (&self.left, &self.right) {
46            (Bound::Included(l), Bound::Included(r)) => format!("[{}, {}]", l.to_string(), r.to_string()),
47            (Bound::Included(l), Bound::Excluded(r)) => format!("[{}, {})", l.to_string(), r.to_string()),
48            (Bound::Excluded(l), Bound::Included(r)) => format!("({}, {}]", l.to_string(), r.to_string()),
49            (Bound::Excluded(l), Bound::Excluded(r)) => format!("({}, {})", l.to_string(), r.to_string()),
50        }
51    }
52}
53
54
55/// A collection of constructors for creating different types of atomic intervals.
56impl<T: Clone + PartialOrd> AtomicInterval<T> {
57    /// Creates an open interval (a,b) that excludes both endpoints.
58    ///
59    /// # Arguments
60    /// * `left` - The left endpoint of the interval
61    /// * `right` - The right endpoint of the interval
62    ///
63    /// # Returns
64    /// A new `AtomicInterval` with excluded endpoints
65    pub fn open(left: T, right: T) -> Self {
66        if left >= right {
67            panic!("The following condition must be valid: `left < right`");
68        }
69        AtomicInterval { left: Bound::Excluded(left), right: Bound::Excluded(right) }
70    }
71
72    /// Creates a closed interval [a,b] that includes both endpoints.
73    ///
74    /// # Arguments
75    /// * `left` - The left endpoint of the interval
76    /// * `right` - The right endpoint of the interval
77    ///
78    /// # Returns
79    /// A new `AtomicInterval` with included endpoints
80    pub fn closed(left: T, right: T) -> Self {
81        if left >= right {
82            panic!("The following condition must be valid: `left < right`");
83        }
84        AtomicInterval { left: Bound::Included(left), right: Bound::Included(right) }
85    }
86
87    /// Creates a left-open, right-closed interval (a,b] that excludes the left endpoint and includes the right endpoint.
88    ///
89    /// # Arguments
90    /// * `left` - The left endpoint of the interval
91    /// * `right` - The right endpoint of the interval
92    ///
93    /// # Returns
94    /// A new `AtomicInterval` with excluded left endpoint and included right endpoint
95    pub fn open_closed(left: T, right: T) -> Self {
96        if left >= right {
97            panic!("The following condition must be valid: `left < right`");
98        }
99        AtomicInterval { left: Bound::Excluded(left), right: Bound::Included(right) }
100    }
101
102    /// Creates a left-closed, right-open interval [a,b) that includes the left endpoint and excludes the right endpoint.
103    ///
104    /// # Arguments
105    /// * `left` - The left endpoint of the interval
106    /// * `right` - The right endpoint of the interval
107    ///
108    /// # Returns
109    /// A new `AtomicInterval` with included left endpoint and excluded right endpoint
110    pub fn closed_open(left: T, right: T) -> Self {
111        if left >= right {
112            panic!("The following condition must be valid: `left < right`");
113        }
114        AtomicInterval { left: Bound::Included(left), right: Bound::Excluded(right) }
115    }
116
117    /// Creates a point interval [a,a] containing a single value.
118    ///
119    /// # Arguments
120    /// * `value` - The value to create a point interval from
121    ///
122    /// # Returns
123    /// A new `AtomicInterval` representing a single point
124    pub fn point(value: T) -> Self {
125        AtomicInterval { left: Bound::Included(value.clone()), right: Bound::Included(value) }
126    }
127}
128
129
130impl<T> AtomicInterval<T> {
131    /// Return a reference to the left bound.
132    /// 
133    /// # Returns
134    /// A reference of `Bound` associated to the left bound.
135    pub fn left(&self) -> &Bound<T> {
136        &self.left
137    }
138
139    /// Return a reference to the right bound.
140    /// 
141    /// # Returns
142    /// A reference of `Bound` associated to the right bound.
143    pub fn right(&self) -> &Bound<T> {
144        &self.right
145    }
146}
147
148/// A collection of methods for performing set operations on atomic intervals.
149impl <T: PartialOrd> AtomicInterval<T> {
150    /// Checks if the interval is a superset of another interval.
151    /// An interval is a superset of another if it contains all the elements of the other interval.
152    /// 
153    /// # Arguments
154    /// * `other` - The other interval to check if it is a subset of the current interval
155    /// 
156    /// # Returns
157    /// `true` if the current interval is a superset of the other interval, `false` otherwise
158    /// 
159    /// # Examples
160    /// ```
161    /// use timekeep_rs::AtomicInterval;
162    ///
163    /// let interval1 = AtomicInterval::closed(1, 5);
164    /// let interval2 = AtomicInterval::closed(2, 4);
165    /// assert!(interval1.is_superset(&interval2));
166    /// ```
167    /// 
168    pub fn is_superset (&self, other: &AtomicInterval<T>) -> bool {
169        match (&self.left, &self.right, &other.left, &other.right) {
170            (Bound::Included(l1), Bound::Excluded(r1), _, Bound::Included(r2)) => l1 <= other.left.value() && r1 > r2,
171            (Bound::Excluded(l1), Bound::Included(r1), Bound::Included(l2), _) => l1 < l2 && r1 >= other.right.value(),
172            (Bound::Excluded(l1), Bound::Excluded(r1), Bound::Included(l2), Bound::Included(r2)) => l1 < l2 && r1 > r2,
173            (_, _, _, _) => self.left.value() <= other.left.value() && self.right.value() >= other.right.value(),
174        }
175    }
176
177    /// Checks if the interval is a subset of another interval.
178    /// An interval is a subset of another if it is contained within the other interval.
179    /// 
180    /// # Arguments
181    /// * `other` - The other interval to check if it is a superset of the current interval
182    ///
183    /// # Returns
184    /// `true` if the current interval is a subset of the other interval, `false` otherwise
185    /// 
186    /// # Examples
187    /// ```
188    /// use timekeep_rs::AtomicInterval;
189    ///
190    /// let interval1 = AtomicInterval::closed(2, 4);
191    /// let interval2 = AtomicInterval::closed(1, 5);
192    /// assert!(interval1.is_subset(&interval2));
193    /// ```
194    /// 
195    pub fn is_subset (&self, other: &AtomicInterval<T>) -> bool {
196        other.is_superset(self)
197    }
198
199    /// Checks if the interval is overlapping with another interval.
200    /// Two intervals are overlapping if they share at least one common point.
201    /// 
202    /// # Arguments
203    /// * `other` - The other interval to check if it is overlapping with the current interval
204    /// 
205    /// # Returns
206    /// `true` if the current interval is overlapping with the other interval, `false` otherwise
207    /// 
208    /// # Examples
209    /// ```
210    /// use timekeep_rs::AtomicInterval;
211    /// 
212    /// let interval1 = AtomicInterval::closed(1, 5);
213    /// let interval2 = AtomicInterval::closed(4, 6);
214    /// assert!(interval1.is_overlapping(&interval2));
215    /// ```
216    /// 
217    pub fn is_overlapping (&self, other: &AtomicInterval<T>) -> bool {
218        // Check if the intervals are overlapping on left side of other
219        let cond1_overlapping = match (&self.left, &self.right, &other.left) {
220            (Bound::Included(l1), Bound::Included(r1), _) => other.left.value() >= l1 && other.left.value() <= r1,
221            (Bound::Included(l1), Bound::Excluded(r1), Bound::Included(l2)) => l2 >= l1 && l2 < r1,
222            (Bound::Included(l1), Bound::Excluded(r1), Bound::Excluded(l2)) => l2 >= l1 && l2 <= r1,
223            (Bound::Excluded(l1), Bound::Included(r1), Bound::Included(l2)) => l2 > l1 && l2 <= r1,
224            (Bound::Excluded(l1), Bound::Included(r1), Bound::Excluded(l2)) => l2 >= l1 && l2 <= r1,
225            (Bound::Excluded(l1), Bound::Excluded(r1), Bound::Included(l2)) => l2 > l1 && l2 < r1,
226            (Bound::Excluded(l1), Bound::Excluded(r1), Bound::Excluded(l2)) => l2 >= l1 && l2 <= r1,
227        };
228        // Check if the intervals are overlapping on right side of other
229        let cond2_overlapping = match (&self.left, &self.right, &other.right) {
230            (Bound::Included(l1), Bound::Included(r1), _) => other.right.value() >= l1 && other.right.value() <= r1,
231            (Bound::Included(l1), Bound::Excluded(r1), Bound::Included(r2)) => r2 > l1 && r2 <= r1,
232            (Bound::Included(l1), Bound::Excluded(r1), Bound::Excluded(r2)) => r2 >= l1 && r2 <= r1,
233            (Bound::Excluded(l1), Bound::Included(r1), Bound::Included(r2)) => r2 >= l1 && r2 < r1,
234            (Bound::Excluded(l1), Bound::Included(r1), Bound::Excluded(r2)) => r2 >= l1 && r2 <= r1,
235            (Bound::Excluded(l1), Bound::Excluded(r1), Bound::Included(r2)) => r2 > l1 && r2 < r1,
236            (Bound::Excluded(l1), Bound::Excluded(r1), Bound::Excluded(r2)) => r2 >= l1 && r2 <= r1,
237        };
238        // They overlap if either condition is true
239        return cond1_overlapping || cond2_overlapping;
240    }
241
242    /// Checks if the interval is adjacent to another interval.
243    /// Two intervals are adjacent if they share a common boundary, but do not overlap.
244    /// 
245    /// # Arguments
246    /// * `other` - The other interval to check if it is adjacent to the current interval
247    /// 
248    /// # Returns
249    /// `true` if the current interval is adjacent to the other interval, `false` otherwise
250    /// 
251    /// # Examples
252    /// ```
253    /// use timekeep_rs::AtomicInterval;
254    /// 
255    /// let interval1 = AtomicInterval::closed(1, 5);
256    /// let interval2 = AtomicInterval::open_closed(5, 10);
257    /// assert!(interval1.is_adjacent(&interval2));
258    /// ```
259    pub fn is_adjacent(&self, other: &AtomicInterval<T>) -> bool {
260        // Check if the intervals are adjacent on left side of other
261        let cond1_adjacent = match (&self.left, &other.right) {
262            (Bound::Excluded(_), Bound::Excluded(_)) => false,
263            (Bound::Included(_), Bound::Included(_)) => false,
264            (_, _) => self.left.value() == other.right.value(),
265        };
266        // Check if the intervals are adjacent on right side of other
267        let cond2_adjacent = match (&self.right, &other.left) {
268            (Bound::Excluded(_), Bound::Excluded(_)) => false,
269            (Bound::Included(_), Bound::Included(_)) => false,
270            (_, _) => self.right.value() == other.left.value(),
271        };
272
273        return cond1_adjacent || cond2_adjacent;
274    }
275
276    /// Checks if the interval is disjoint from another interval.
277    /// Two intervals are disjoint if they do not share any common points.
278    /// 
279    /// # Arguments
280    /// * `other` - The other interval to check if it is disjoint from the current interval
281    /// 
282    /// # Returns
283    /// `true` if the current interval is disjoint from the other interval, `false` otherwise
284    /// 
285    /// # Examples
286    /// ```
287    /// use timekeep_rs::AtomicInterval;
288    /// 
289    /// let interval1 = AtomicInterval::closed(1, 5);
290    /// let interval2 = AtomicInterval::closed(6, 10);
291    /// assert!(interval1.is_disjoint(&interval2));
292    /// ```
293    /// 
294    pub fn is_disjoint(&self, other: &AtomicInterval<T>) -> bool {
295        // Check if the intervals are disjoint on one side
296        let cond1_disjoint = match (&self.left, &other.right) {
297            (Bound::Included(l1), Bound::Included(r2)) => l1 > r2,
298            (_, _) => return self.right.value() <= other.left.value(),
299        };
300
301        // Check if the intervals are disjoint on the other side
302        let cond2_disjoint = match (&self.right, &other.left) {
303            (Bound::Included(r1), Bound::Included(l2)) => r1 < l2,
304            (_, _) => return self.left.value() >= other.right.value(),
305        };
306
307        return cond1_disjoint || cond2_disjoint;
308    }
309}
310
311impl <T: PartialOrd + Clone> AtomicInterval<T> {
312    /// Computes the union of two overlapping or adjacent intervals.
313    /// The union of two intervals is the smallest interval that contains both intervals.
314    /// 
315    /// # Arguments
316    /// * `a` - The first interval to union
317    /// * `b` - The second interval to union
318    /// 
319    /// # Returns
320    /// A `Vec` containing the union of the two intervals if they are overlapping or adjacent, an empty `Vec` otherwise
321    /// 
322    /// # Examples
323    /// ```
324    /// use timekeep_rs::AtomicInterval;
325    /// 
326    /// let interval1 = AtomicInterval::closed(1, 5);
327    /// let interval2 = AtomicInterval::closed(4, 7);
328    /// let merged = AtomicInterval::union(&interval1, &interval2);
329    /// 
330    /// assert_eq!(merged.len(), 1);
331    /// assert_eq!(merged.first().unwrap(), &AtomicInterval::closed(1, 7));
332    /// ```
333    /// 
334    pub fn union(a: &AtomicInterval<T>, b: &AtomicInterval<T>) -> Vec<AtomicInterval<T>> {
335        if a.is_overlapping(b) || a.is_adjacent(b) {
336            let left = if a.left.value() <= b.left.value() {
337                a.left.clone()
338            } else {
339                b.left.clone()
340            };
341            let right = if a.right.value() >= b.right.value() {
342                a.right.clone()
343            } else {
344                b.right.clone()
345            };
346            vec![AtomicInterval { left, right }]
347        } else {
348            vec![]
349        }
350    }
351
352    /// Computes the intersection of two overlapping intervals.
353    /// The intersection of two intervals is the largest interval that is contained within both intervals.
354    /// 
355    /// # Arguments
356    /// * `other` - The other interval to intersect with the current interval
357    /// 
358    /// # Returns
359    /// A `Vec` containing the intersection of the two intervals if they are overlapping, an empty `Vec` otherwise
360    /// 
361    /// # Examples
362    /// ```
363    /// use timekeep_rs::AtomicInterval;
364    /// 
365    /// let interval1 = AtomicInterval::closed(1, 5);
366    /// let interval2 = AtomicInterval::closed(3, 7);
367    /// let intersection = interval1.intersection(&interval2);
368    /// 
369    /// assert_eq!(intersection.len(), 1);
370    /// assert_eq!(intersection.first().unwrap(), &AtomicInterval::closed(3, 5));
371    /// ```
372    /// 
373    pub fn intersection(&self, other: &Self) -> Vec<Self> {
374        // If they're disjoint, there's no intersection.
375        if self.is_disjoint(other) {
376            return vec![];
377        }
378
379        // Determine the left boundary of the intersection.
380        let left = if self.left.value() > other.left.value() {
381            self.left.clone()
382        } else {
383            other.left.clone()
384        };
385
386        // Determine the right boundary of the intersection.
387        let right = if self.right.value() < other.right.value() {
388            self.right.clone()
389        } else {
390            other.right.clone()
391        };
392
393        // If they meet at a single point, ensure it's included on both sides.
394        if left.value() == right.value() {
395            return match (left, right) {
396                (Bound::Included(val), Bound::Included(_)) => {
397                    vec![ AtomicInterval { left: Bound::Included(val.clone()), right: Bound::Included(val) } ]
398                }
399                _ => vec![],
400            };
401        }
402
403        // Otherwise, we have a valid overlapping range.
404        vec![ AtomicInterval { left, right } ]
405    }
406
407    /// Computes the difference between two intervals.
408    /// The difference between two intervals is the set of intervals that are in the first interval but not in the second interval.
409    /// 
410    /// # Arguments
411    /// * `other` - The other interval to compute the difference with the current interval
412    /// 
413    /// # Returns
414    /// A `Vec` of `AtomicInterval` representing the difference between the two intervals
415    /// 
416    /// # Examples
417    /// ```
418    /// use timekeep_rs::AtomicInterval;
419    /// 
420    /// let interval1 = AtomicInterval::closed(1, 5);
421    /// let interval2 = AtomicInterval::closed(3, 7);
422    /// let difference = interval1.difference(&interval2);
423    /// assert_eq!(difference.len(), 1);
424    /// assert_eq!(difference[0], AtomicInterval::closed_open(1, 3));
425    /// ```
426    /// 
427    pub fn difference(&self, other: &Self) -> Vec<Self> {
428        // If disjoint, difference is just self.
429        if self.is_disjoint(other) {
430            return vec![self.clone()];
431        } else if self.is_subset(other) {
432            return vec![];
433        }
434
435        // If there's no intersection, difference is self.
436        let intersection_vec = self.intersection(other);
437        let intersection = intersection_vec.first().expect("No intersection found!");
438
439        let mut result = Vec::new();
440
441        // Left remainder: from self.left up to intersection.left (if any).
442        if intersection.left.value() > self.left.value() {
443            let left_interval = AtomicInterval {
444                left: self.left.clone(),
445                right: match &intersection.left {
446                    Bound::Included(val) => Bound::Excluded(val.clone()),
447                    Bound::Excluded(val) => Bound::Excluded(val.clone()),
448                },
449            };
450            // Only add if valid (left <= right).
451            if left_interval.left.value() < left_interval.right.value() {
452                result.push(left_interval);
453            }
454        }
455
456        // Right remainder: from intersection.right up to self.right (if any).
457        if intersection.right.value() < self.right.value() {
458            let right_interval = AtomicInterval {
459                left: match &intersection.right {
460                    Bound::Included(val) => Bound::Excluded(val.clone()),
461                    Bound::Excluded(val) => Bound::Excluded(val.clone()),
462                },
463                right: self.right.clone(),
464            };
465            // Only add if valid (left <= right).
466            if right_interval.left.value() < right_interval.right.value() {
467                result.push(right_interval);
468            }
469        }
470
471        result
472    }
473
474}
475
476#[cfg(test)]
477mod tests {
478    use super::*;
479
480    #[test]
481    fn test_open_interval() {
482        let interval = AtomicInterval::open(1, 5);
483        assert_eq!(interval.left, Bound::Excluded(1));
484        assert_eq!(interval.right, Bound::Excluded(5));
485    }
486
487    #[test]
488    fn test_closed_interval() {
489        let interval = AtomicInterval::closed(1, 5);
490        assert_eq!(interval.left, Bound::Included(1));
491        assert_eq!(interval.right, Bound::Included(5));
492    }
493
494    #[test]
495    fn test_open_closed_interval() {
496        let interval = AtomicInterval::open_closed(1, 5);
497        assert_eq!(interval.left, Bound::Excluded(1));
498        assert_eq!(interval.right, Bound::Included(5));
499    }
500
501    #[test]
502    fn test_closed_open_interval() {
503        let interval = AtomicInterval::closed_open(1, 5);
504        assert_eq!(interval.left, Bound::Included(1));
505        assert_eq!(interval.right, Bound::Excluded(5));
506    }
507
508    #[test]
509    fn test_point_interval() {
510        let interval = AtomicInterval::point(1);
511        assert_eq!(interval.left, Bound::Included(1));
512        assert_eq!(interval.right, Bound::Included(1));
513    }
514
515    #[test]
516    fn test_is_overlapping() {
517        let interval1 = AtomicInterval::closed(1, 5);
518        let interval2 = AtomicInterval::closed(4, 6);
519        assert!(interval1.is_overlapping(&interval2));
520    }
521
522    #[test]
523    fn test_is_adjacent() {
524        let interval1 = AtomicInterval::closed(1, 5);
525        let interval2 = AtomicInterval::open_closed(5, 10);
526        assert!(interval1.is_adjacent(&interval2));
527    }
528
529    #[test]
530    fn test_is_disjoint() {
531        let interval1 = AtomicInterval::closed(1, 5);
532        let interval2 = AtomicInterval::closed(6, 10);
533        assert!(interval1.is_disjoint(&interval2));
534    }
535
536    #[test]
537    fn test_is_subset() {
538        let interval1 = AtomicInterval::closed(2, 4);
539        let interval2 = AtomicInterval::closed(1, 5);
540        assert!(interval1.is_subset(&interval2));
541    }
542
543    #[test]
544    fn test_is_superset() {
545        let interval1 = AtomicInterval::closed(1, 5);
546        let interval2 = AtomicInterval::closed(2, 4);
547        assert!(interval1.is_superset(&interval2));
548    }
549
550    #[test]
551    fn test_union_overlapping_intervals() {
552        let interval1 = AtomicInterval::closed(1, 5);
553        let interval2 = AtomicInterval::closed(4, 7);
554        let merged = AtomicInterval::union(&interval1, &interval2);
555        assert_eq!(merged.len(), 1);
556        assert_eq!(merged.first().unwrap(), &AtomicInterval::closed(1, 7));
557    }
558
559    #[test]
560    fn test_union_adjacent_intervals() {
561        let interval1 = AtomicInterval::closed(1, 5);
562        let interval2 = AtomicInterval::closed(5, 7);
563        let merged = AtomicInterval::union(&interval1, &interval2);
564        assert_eq!(merged.len(), 1);
565        assert_eq!(merged.first().unwrap(), &AtomicInterval::closed(1, 7));
566    }
567
568    #[test]
569    fn test_union_disjoint_intervals() {
570        let interval1 = AtomicInterval::closed(1, 5);
571        let interval2 = AtomicInterval::closed(6, 7);
572        let merged = AtomicInterval::union(&interval1, &interval2);
573        assert_eq!(merged.len(), 0);
574    }
575
576    #[test]
577    fn test_intersection_between_two_overlapping_intervals() {
578        let interval1 = AtomicInterval::closed(1, 5);
579        let interval2 = AtomicInterval::closed(3, 7);
580        let intersection = interval1.intersection(&interval2);
581        assert_eq!(intersection.len(), 1);
582        assert_eq!(intersection.first().unwrap(), &AtomicInterval::closed(3, 5));
583    }
584
585    #[test]
586    fn test_intersection_between_two_disjoint_intervals() {
587        let interval1 = AtomicInterval::closed(1, 3);
588        let interval2 = AtomicInterval::closed(4, 7);
589        let intersection = interval1.intersection(&interval2);
590        assert_eq!(intersection.len(), 0);
591    }
592
593    #[test]
594    fn test_intersection_between_two_adjacent_intervals() {
595        let interval1 = AtomicInterval::closed(1, 5);
596        let interval2 = AtomicInterval::open(5, 7);
597        let intersection = interval1.intersection(&interval2);
598        assert_eq!(intersection.len(), 0);
599    }
600
601    #[test]
602    fn test_difference_between_two_overlapping_intervals() {
603        let interval1 = AtomicInterval::closed(1, 5);
604        let interval2 = AtomicInterval::closed(3, 7);
605        let difference = interval1.difference(&interval2);
606        assert_eq!(difference.len(), 1);
607        assert_eq!(difference[0], AtomicInterval::closed_open(1, 3));
608    }
609
610    #[test]
611    fn test_difference_between_subset_and_superset_interval() {
612        let interval1 = AtomicInterval::closed(1, 5);
613        let interval2 = AtomicInterval::closed(2, 4);
614        let difference = interval1.difference(&interval2);
615        assert_eq!(difference.len(), 2);
616        assert_eq!(difference[0], AtomicInterval::closed_open(1, 2));
617        assert_eq!(difference[1], AtomicInterval::open_closed(4, 5));
618    }
619
620    #[test]
621    fn test_difference_between_two_disjoint_intervals() {
622        let interval1 = AtomicInterval::closed(1, 3);
623        let interval2 = AtomicInterval::closed(4, 7);
624        let difference = interval1.difference(&interval2);
625        assert_eq!(difference.len(), 1);
626        assert_eq!(difference[0], AtomicInterval::closed(1, 3));
627    }
628
629    #[test]
630    fn test_difference_between_two_adjacent_intervals() {
631        let interval1 = AtomicInterval::closed(1, 5);
632        let interval2 = AtomicInterval::open(5, 7);
633        let difference = interval1.difference(&interval2);
634        assert_eq!(difference.len(), 1);
635        assert_eq!(difference[0], AtomicInterval::closed(1, 5));
636    }
637}