ranges/generic_range/
union.rs

1use core::ops::BitOr;
2
3use crate::{Arrangement, Domain, GenericRange, OperationResult};
4
5impl<T: Domain> GenericRange<T> {
6    /// Results in either a single or, if the inputs are disjoint, two ranges.
7    ///
8    /// # Examples
9    /// Disjoint ranges.
10    /// ```
11    /// use ranges::{GenericRange, OperationResult};
12    ///
13    /// let range = GenericRange::new_less_than(5);
14    /// let range2 = GenericRange::new_at_least(10);
15    ///
16    /// assert_eq!(range | range2, OperationResult::Double(range, range2));
17    /// ```
18    /// Overlapping ranges.
19    /// ```
20    /// use ranges::{GenericRange, OperationResult};
21    ///
22    /// let range = GenericRange::from(0..10);
23    /// let range2 = 5..=15;
24    ///
25    /// assert_eq!(range | range2, OperationResult::Single((0..=15).into()));
26    /// ```
27    pub fn union(self, other: Self) -> OperationResult<T> {
28        // we can directly create `Self` in all arms because the required `(start <= end)`
29        // assertion is already proven by correctly returning `first` and `second` in self.arrangement()
30        match self.arrangement(&other) {
31            Arrangement::Disjoint { self_less: true } => OperationResult::Double(self, other),
32            Arrangement::Disjoint { self_less: false } => OperationResult::Double(other, self),
33            Arrangement::Touching { self_less: true } | Arrangement::Overlapping { self_less: true, .. } => {
34                OperationResult::Single(Self {
35                    start: self.start,
36                    end: other.end,
37                })
38            }
39            Arrangement::Touching { self_less: false } | Arrangement::Overlapping { self_less: false, .. } => {
40                OperationResult::Single(Self {
41                    start: other.start,
42                    end: self.end,
43                })
44            }
45            Arrangement::Containing { self_shorter: false }
46            | Arrangement::Starting {
47                self_shorter: false, ..
48            }
49            | Arrangement::Ending {
50                self_shorter: false, ..
51            }
52            | Arrangement::Equal
53            | Arrangement::Empty {
54                self_empty: Some(false),
55            } => OperationResult::Single(self),
56            Arrangement::Containing { self_shorter: true }
57            | Arrangement::Starting { self_shorter: true, .. }
58            | Arrangement::Ending { self_shorter: true, .. }
59            | Arrangement::Empty { self_empty: Some(true) } => OperationResult::Single(other),
60            Arrangement::Empty { self_empty: None } => OperationResult::Empty,
61        }
62    }
63}
64
65/// This calls [`self.union(other)`](#method.union).
66impl<T, I> BitOr<I> for GenericRange<T>
67where
68    I: Into<GenericRange<T>>,
69    T: Domain,
70{
71    type Output = OperationResult<T>;
72
73    #[must_use]
74    fn bitor(self, rhs: I) -> Self::Output {
75        self.union(rhs.into())
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use crate::{GenericRange, OperationResult};
82
83    #[test]
84    fn disjoint() {
85        let range = GenericRange::new_less_than(5);
86        let range2 = GenericRange::new_at_least(10);
87
88        assert_eq!(range.union(range2), OperationResult::Double(range, range2));
89        assert_eq!(range2.union(range), OperationResult::Double(range, range2));
90
91        assert_eq!(range | range2, OperationResult::Double(range, range2));
92        assert_eq!(range2 | range, OperationResult::Double(range, range2));
93    }
94
95    #[test]
96    fn touching() {
97        let range = GenericRange::from(0..10);
98        let range2 = GenericRange::from(10..=20);
99
100        assert_eq!(range.union(range2), OperationResult::Single(GenericRange::from(0..=20)));
101        assert_eq!(range2.union(range), OperationResult::Single(GenericRange::from(0..=20)));
102
103        assert_eq!(range | range2, OperationResult::Single(GenericRange::from(0..=20)));
104        assert_eq!(range2 | range, OperationResult::Single(GenericRange::from(0..=20)));
105    }
106
107    #[test]
108    fn overlapping() {
109        let range = GenericRange::from(0..10);
110        let range2 = GenericRange::from(5..=15);
111
112        assert_eq!(range.union(range2), OperationResult::Single(GenericRange::from(0..=15)));
113        assert_eq!(range2.union(range), OperationResult::Single(GenericRange::from(0..=15)));
114
115        assert_eq!(range | range2, OperationResult::Single(GenericRange::from(0..=15)));
116        assert_eq!(range2 | range, OperationResult::Single(GenericRange::from(0..=15)));
117    }
118
119    #[test]
120    fn containing() {
121        let range = GenericRange::from(0..10);
122        let range2 = GenericRange::from(5..=8);
123
124        assert_eq!(range.union(range2), OperationResult::Single(range));
125        assert_eq!(range2.union(range), OperationResult::Single(range));
126
127        assert_eq!(range | range2, OperationResult::Single(range));
128        assert_eq!(range2 | range, OperationResult::Single(range));
129    }
130
131    #[test]
132    fn starting() {
133        let range = GenericRange::from(0..10);
134        let range2 = GenericRange::from(0..=8);
135
136        assert_eq!(range.union(range2), OperationResult::Single(range));
137        assert_eq!(range2.union(range), OperationResult::Single(range));
138
139        assert_eq!(range | range2, OperationResult::Single(range));
140        assert_eq!(range2 | range, OperationResult::Single(range));
141    }
142
143    #[test]
144    fn ending() {
145        let range = GenericRange::from(3..=10);
146        let range2 = GenericRange::from(5..=10);
147
148        assert_eq!(range.union(range2), OperationResult::Single(range));
149        assert_eq!(range2.union(range), OperationResult::Single(range));
150
151        assert_eq!(range | range2, OperationResult::Single(range));
152        assert_eq!(range2 | range, OperationResult::Single(range));
153    }
154
155    #[test]
156    fn equal() {
157        let range = GenericRange::from(5..=10);
158        let range2 = range;
159
160        assert_eq!(range.union(range2), OperationResult::Single(range));
161        assert_eq!(range2.union(range), OperationResult::Single(range));
162
163        assert_eq!(range | range2, OperationResult::Single(range));
164        assert_eq!(range2 | range, OperationResult::Single(range));
165    }
166}