1use core::ops::{
4 Bound,
5 Range,
6 RangeBounds,
7};
8
9pub trait RangeExt<T>: RangeBounds<T>
11where T: Ord
12{
13 fn normalize(
31 self,
32 start: impl Into<Option<T>>,
33 end: impl Into<Option<T>>,
34 ) -> Range<T>;
35
36 fn intersection<R>(self, other: R) -> Option<Range<T>>
42 where R: RangeExt<T>;
43
44 fn union<R>(self, other: R) -> Option<Range<T>>
50 where R: RangeExt<T>;
51}
52
53impl<R> RangeExt<usize> for R
55where R: RangeBounds<usize>
56{
57 fn normalize(
58 self,
59 start: impl Into<Option<usize>>,
60 end: impl Into<Option<usize>>,
61 ) -> Range<usize> {
62 let start = match self.start_bound() {
63 Bound::Unbounded => start.into().unwrap_or(0),
64 Bound::Included(&v) => v,
65 Bound::Excluded(&v) => v.saturating_add(1),
66 };
67 let end = match self.end_bound() {
68 Bound::Unbounded => end.into().unwrap_or(!0),
69 Bound::Included(&v) => v.saturating_add(1),
70 Bound::Excluded(&v) => v,
71 };
72 if start > end {
73 end .. start
74 }
75 else {
76 start .. end
77 }
78 }
79
80 fn intersection<R2>(self, other: R2) -> Option<Range<usize>>
81 where R2: RangeExt<usize> {
82 let Range { start: a1, end: a2 } = self.normalize(None, None);
83 let Range { start: b1, end: b2 } = other.normalize(None, None);
84 if b1 < a1 {
85 return (b1 .. b2).intersection(a1 .. a2);
86 }
87 if !(a1 .. a2).contains(&b1) {
88 return None;
89 }
90 let start = a1.max(b1);
91 let end = a2.min(b2);
92 if start > end {
93 Some(end .. start)
94 }
95 else {
96 Some(start .. end)
97 }
98 }
99
100 fn union<R2>(self, other: R2) -> Option<Range<usize>>
101 where R2: RangeExt<usize> {
102 let Range { start: a1, end: a2 } = self.normalize(None, None);
103 let Range { start: b1, end: b2 } = other.normalize(None, None);
104 if b1 < a1 {
105 return (b1 .. b2).intersection(a1 .. a2);
106 }
107 if !(a1 .. a2).contains(&b1) {
108 return None;
109 }
110 let start = a1.min(b1);
111 let end = a2.max(b2);
112 if start > end {
113 Some(end .. start)
114 }
115 else {
116 Some(start .. end)
117 }
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn normalize() {
127 let r = (..).normalize(1, 10);
128 assert!(r.contains(&1));
129 assert!(r.contains(&9));
130 assert!(!r.contains(&0));
131 assert!(!r.contains(&10));
132
133 let r = (.. 10).normalize(1, 20);
134 assert!(r.contains(&1));
135 assert!(r.contains(&9));
136 assert!(!r.contains(&0));
137 assert!(!r.contains(&10));
138
139 let r = (4 ..).normalize(6, 10);
140 assert!(r.contains(&4));
141 assert!(r.contains(&9));
142 assert!(!r.contains(&3));
143 assert!(!r.contains(&10));
144
145 let r = (4 ..= 10).normalize(6, 8);
146 assert!(r.contains(&4));
147 assert!(r.contains(&10));
148 assert!(!r.contains(&3));
149 assert!(!r.contains(&11));
150
151 let r = (..= 10).normalize(1, 8);
152 assert!(r.contains(&1));
153 assert!(r.contains(&10));
154 assert!(!r.contains(&0));
155 assert!(!r.contains(&11));
156 }
157
158 #[test]
159 fn intersect() {
160 let a = 3 .. 10;
161 let b = 7 ..= 20;
162 assert_eq!(a.intersection(b), Some(7 .. 10));
163
164 let c = 3 .. 10;
165 let d = 13 ..= 20;
166 assert!(c.intersection(d).is_none());
167 }
168
169 #[test]
170 fn union() {
171 let a = 3 .. 10;
172 let b = 7 ..= 20;
173 assert_eq!(a.union(b), Some(3 .. 21));
174
175 let c = 3 .. 10;
176 let d = 13 ..= 20;
177 assert!(c.union(d).is_none());
178 }
179}