willow_data_model/grouping/
range.rs1use core::cmp;
2use core::cmp::Ordering;
3
4#[cfg(feature = "dev")]
5use arbitrary::{Arbitrary, Error as ArbitraryError};
6
7use crate::path::Path;
8
9#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
10#[cfg_attr(feature = "dev", derive(Arbitrary))]
11pub enum RangeEnd<T> {
13 Closed(T),
15 Open,
17}
18
19impl<T: PartialOrd> RangeEnd<T> {
20 pub fn gt_val(&self, val: &T) -> bool {
22 match self {
23 RangeEnd::Open => true,
24 RangeEnd::Closed(end_val) => end_val > val,
25 }
26 }
27}
28
29impl From<&RangeEnd<u64>> for u64 {
30 fn from(value: &RangeEnd<u64>) -> Self {
31 match value {
32 RangeEnd::Closed(val) => *val,
33 RangeEnd::Open => u64::MAX,
34 }
35 }
36}
37
38impl<T: Ord> Ord for RangeEnd<T> {
39 fn cmp(&self, other: &Self) -> Ordering {
40 match self {
41 RangeEnd::Closed(end_value) => match other {
42 RangeEnd::Closed(other_end_value) => end_value.cmp(other_end_value),
43 RangeEnd::Open => Ordering::Less,
44 },
45 RangeEnd::Open => match other {
46 RangeEnd::Closed(_) => Ordering::Greater,
47 RangeEnd::Open => Ordering::Equal,
48 },
49 }
50 }
51}
52
53impl<T: PartialOrd> PartialOrd for RangeEnd<T> {
54 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
55 match self {
56 RangeEnd::Closed(end_value) => match other {
57 RangeEnd::Closed(other_end_value) => end_value.partial_cmp(other_end_value),
58 RangeEnd::Open => Some(Ordering::Less),
59 },
60 RangeEnd::Open => match other {
61 RangeEnd::Closed(_) => Some(Ordering::Greater),
62 RangeEnd::Open => Some(Ordering::Equal),
63 },
64 }
65 }
66}
67
68impl<T> PartialEq<T> for RangeEnd<T>
69where
70 T: PartialEq,
71{
72 fn eq(&self, other: &T) -> bool {
73 match self {
74 RangeEnd::Closed(val) => val.eq(other),
75 RangeEnd::Open => false,
76 }
77 }
78}
79
80impl<T> PartialOrd<T> for RangeEnd<T>
81where
82 T: PartialOrd,
83{
84 fn partial_cmp(&self, other: &T) -> Option<Ordering> {
85 match self {
86 RangeEnd::Closed(val) => val.partial_cmp(other),
87 RangeEnd::Open => Some(Ordering::Greater),
88 }
89 }
90}
91
92impl PartialEq<RangeEnd<u64>> for u64 {
93 fn eq(&self, other: &RangeEnd<u64>) -> bool {
94 match other {
95 RangeEnd::Closed(other_val) => self.eq(other_val),
96 RangeEnd::Open => false,
97 }
98 }
99}
100
101impl PartialOrd<RangeEnd<u64>> for u64 {
102 fn partial_cmp(&self, other: &RangeEnd<u64>) -> Option<Ordering> {
103 match other {
104 RangeEnd::Closed(other_val) => self.partial_cmp(other_val),
105 RangeEnd::Open => Some(Ordering::Less),
106 }
107 }
108}
109
110impl<const MCL: usize, const MCC: usize, const MPL: usize> PartialEq<RangeEnd<Path<MCL, MCC, MPL>>>
111 for Path<MCL, MCC, MPL>
112{
113 fn eq(&self, other: &RangeEnd<Path<MCL, MCC, MPL>>) -> bool {
114 match other {
115 RangeEnd::Closed(other_path) => self.eq(other_path),
116 RangeEnd::Open => false,
117 }
118 }
119}
120
121impl<const MCL: usize, const MCC: usize, const MPL: usize> PartialOrd<RangeEnd<Path<MCL, MCC, MPL>>>
122 for Path<MCL, MCC, MPL>
123{
124 fn partial_cmp(&self, other: &RangeEnd<Path<MCL, MCC, MPL>>) -> Option<Ordering> {
125 match other {
126 RangeEnd::Closed(other_path) => self.partial_cmp(other_path),
127 RangeEnd::Open => Some(Ordering::Less),
128 }
129 }
130}
131
132#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
136pub struct Range<T> {
137 pub start: T,
139 pub end: RangeEnd<T>,
141}
142
143impl<T> Range<T> {
144 pub fn new(start: T, end: RangeEnd<T>) -> Self {
146 Self { start, end }
147 }
148
149 pub fn new_open(start: T) -> Self {
151 Self {
152 start,
153 end: RangeEnd::Open,
154 }
155 }
156}
157
158impl<T> Range<T>
159where
160 T: PartialOrd,
161{
162 pub fn new_closed(start: T, end: T) -> Option<Self> {
164 if start < end {
165 return Some(Self {
166 start,
167 end: RangeEnd::Closed(end),
168 });
169 }
170
171 None
172 }
173
174 pub fn includes(&self, value: &T) -> bool {
176 &self.start <= value && self.end.gt_val(value)
177 }
178
179 pub fn includes_range(&self, other: &Range<T>) -> bool {
181 self.start <= other.start && self.end >= other.end
182 }
183}
184impl<T> Range<T>
185where
186 T: Ord + Clone,
187{
188 pub fn intersection(&self, other: &Self) -> Option<Self> {
190 let start = cmp::max(&self.start, &other.start);
191 let end = match (&self.end, &other.end) {
192 (RangeEnd::Open, RangeEnd::Closed(b)) => RangeEnd::Closed(b),
193 (RangeEnd::Closed(a), RangeEnd::Closed(b)) => RangeEnd::Closed(a.min(b)),
194 (RangeEnd::Closed(a), RangeEnd::Open) => RangeEnd::Closed(a),
195 (RangeEnd::Open, RangeEnd::Open) => RangeEnd::Open,
196 };
197 match end {
198 RangeEnd::Open => Some(Self::new_open(start.clone())),
199 RangeEnd::Closed(t) if t >= start => {
200 Some(Self::new_closed(start.clone(), t.clone()).unwrap())
201 }
202 RangeEnd::Closed(_) => None,
203 }
204 }
205}
206
207impl<T: Default> Range<T> {
208 pub fn full() -> Self {
210 Self::new_open(T::default())
211 }
212}
213
214impl<T: Default> Default for Range<T> {
215 fn default() -> Self {
216 Self::full()
217 }
218}
219
220impl<T: Ord> Ord for Range<T> {
221 fn cmp(&self, other: &Self) -> Ordering {
222 match self.start.cmp(&other.start) {
223 Ordering::Less => Ordering::Less,
224 Ordering::Equal => Ordering::Equal,
225 Ordering::Greater => self.end.cmp(&other.end),
226 }
227 }
228}
229
230impl<T: PartialOrd> PartialOrd for Range<T> {
231 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
232 match self.start.partial_cmp(&other.start) {
233 None => None,
234 Some(Ordering::Less) => Some(Ordering::Less),
235 Some(Ordering::Equal) => Some(Ordering::Equal),
236 Some(Ordering::Greater) => self.end.partial_cmp(&other.end),
237 }
238 }
239}
240
241#[cfg(feature = "dev")]
242impl<'a, T> Arbitrary<'a> for Range<T>
243where
244 T: Arbitrary<'a> + PartialOrd,
245{
246 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
247 let start: T = Arbitrary::arbitrary(u)?;
248 let end: RangeEnd<T> = Arbitrary::arbitrary(u)?;
249
250 if !end.gt_val(&start) {
251 return Err(ArbitraryError::IncorrectFormat);
252 }
253
254 Ok(Self { start, end })
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use super::*;
261
262 #[test]
265 fn range_end_ord() {
266 assert!(RangeEnd::Closed(0) == RangeEnd::Closed(0));
267 assert!(RangeEnd::Closed(1) < RangeEnd::Closed(2));
268 assert!(RangeEnd::Closed(100) < RangeEnd::Open);
269 assert!(RangeEnd::<usize>::Open == RangeEnd::Open);
270 }
271
272 #[test]
275 fn range_new_closed() {
276 assert!(Range::new_closed(0, 0).is_none());
277 assert!(Range::new_closed(2, 1).is_none());
278 assert!(Range::new_closed(5, 10).is_some());
279 }
280
281 #[test]
282 fn range_includes() {
283 let open_range = Range::new_open(20);
284
285 assert!(open_range.includes(&20));
286 assert!(open_range.includes(&30));
287 assert!(!open_range.includes(&10));
288
289 let closed_range = Range::new_closed(5, 10).unwrap();
290
291 assert!(closed_range.includes(&5));
292 assert!(closed_range.includes(&8));
293 assert!(!closed_range.includes(&1));
294 }
295
296 #[test]
297 fn range_includes_range() {
298 let open_range = Range::new_open(0);
299 let open_range_2 = Range::new_open(2);
300
301 assert!(open_range.includes_range(&open_range_2));
302 assert!(!open_range_2.includes_range(&open_range));
303
304 let closed_range = Range::new_closed(0, 10).unwrap();
305 let closed_range_2 = Range::new_closed(5, 10).unwrap();
306 let closed_range_3 = Range::new_closed(5, 15).unwrap();
307
308 assert!(closed_range.includes_range(&closed_range_2));
309 assert!(!closed_range_2.includes_range(&closed_range));
310 assert!(!closed_range.includes_range(&closed_range_3));
311
312 assert!(open_range.includes_range(&closed_range));
313 assert!(!closed_range.includes_range(&open_range_2));
314 }
315
316 #[test]
317 fn range_intersection() {
318 let closed_1 = Range::new_closed(0, 10).unwrap();
319 let closed_2 = Range::new_closed(5, 15).unwrap();
320
321 let intersection_1 = closed_1.intersection(&closed_2);
322
323 assert!(intersection_1.is_some());
324 assert_eq!(intersection_1.unwrap(), Range::new_closed(5, 10).unwrap());
325
326 let open_1 = Range::new_open(5);
327
328 let intersection_2 = open_1.intersection(&closed_1);
329
330 assert!(intersection_2.is_some());
331 assert_eq!(intersection_2.unwrap(), Range::new_closed(5, 10).unwrap());
332
333 let closed_3 = Range::new_closed(20, 25).unwrap();
334
335 let intersection_3 = closed_3.intersection(&closed_1);
336
337 assert!(intersection_3.is_none());
338
339 let open_2 = Range::new_open(50);
340
341 let intersection_4 = closed_3.intersection(&open_2);
342
343 assert!(intersection_4.is_none())
344 }
345}