1use super::{
2 direct_bound_cmp, direct_bound_partial_cmp, direct_bound_partial_eq, is_range_empty, max_bound,
3 min_bound, AsRange, Bound, BoundOrdering, Directed, Measure,
4};
5use range_traits::{Bounded, MaybeBounded, PartialEnum};
6use std::{
7 cmp::{Ord, Ordering, PartialOrd},
8 fmt,
9 hash::{Hash, Hasher},
10 ops::RangeBounds,
11};
12
13#[derive(Clone, Copy)]
14pub struct AnyRange<T> {
15 pub start: Bound<T>,
16 pub end: Bound<T>,
17}
18
19impl<T> AnyRange<T> {
20 pub fn new(start: Bound<T>, end: Bound<T>) -> Self {
21 Self { start, end }
22 }
23
24 pub fn from<R: AsRange<Item = T>>(range: R) -> AnyRange<T>
25 where
26 T: Clone,
27 {
28 AnyRange {
29 start: range.start().cloned(),
30 end: range.end().cloned(),
31 }
32 }
33
34 pub fn into_bounds(self) -> (Bound<T>, Bound<T>) {
35 (self.start, self.end)
36 }
37
38 pub fn is_empty(&self) -> bool
39 where
40 T: Measure + PartialEnum,
41 {
42 is_range_empty(self.start_bound(), self.end_bound())
43 }
44
45 pub fn len(&self) -> T::Len
46 where
47 T: Measure + Bounded,
48 {
49 match (self.start_bound(), self.end_bound()) {
50 (Bound::Included(a), Bound::Included(b)) => a.distance(b) + b.len(),
51 (Bound::Included(a), Bound::Excluded(b)) => a.distance(b),
52 (Bound::Included(a), Bound::Unbounded) => a.distance(&T::max()),
53 (Bound::Excluded(a), Bound::Included(b)) => a.distance(b) - a.len() + b.len(),
54 (Bound::Excluded(a), Bound::Excluded(b)) => a.distance(b) - a.len(),
55 (Bound::Excluded(a), Bound::Unbounded) => a.distance(&T::max()) - a.len(),
56 (Bound::Unbounded, Bound::Included(b)) => T::min().distance(b) + b.len(),
57 (Bound::Unbounded, Bound::Excluded(b)) => T::min().distance(b),
58 (Bound::Unbounded, Bound::Unbounded) => T::min().distance(&T::max()),
59 }
60 }
61
62 pub fn bounded_len(&self) -> Option<T::Len>
63 where
64 T: Measure + MaybeBounded,
65 {
66 match (self.start_bound(), self.end_bound()) {
67 (Bound::Included(a), Bound::Included(b)) => Some(a.distance(b) + b.len()),
68 (Bound::Included(a), Bound::Excluded(b)) => Some(a.distance(b)),
69 (Bound::Included(a), Bound::Unbounded) => T::max().map(|m| a.distance(&m)),
70 (Bound::Excluded(a), Bound::Included(b)) => Some(a.distance(b) - a.len() + b.len()),
71 (Bound::Excluded(a), Bound::Excluded(b)) => Some(a.distance(b) - a.len()),
72 (Bound::Excluded(a), Bound::Unbounded) => T::max().map(|m| a.distance(&m) - a.len()),
73 (Bound::Unbounded, Bound::Included(b)) => T::min().map(|m| m.distance(b) + b.len()),
74 (Bound::Unbounded, Bound::Excluded(b)) => T::min().map(|m| m.distance(b)),
75 (Bound::Unbounded, Bound::Unbounded) => {
76 T::min().and_then(|min| T::max().map(|max| min.distance(&max)))
77 }
78 }
79 }
80
81 pub fn pick(&self) -> Option<T>
82 where
83 T: Clone + Measure + PartialEnum + Bounded,
84 {
85 self.first().or_else(|| self.last())
86 }
87
88 pub fn first(&self) -> Option<T>
90 where
91 T: Clone + Measure + PartialEnum + Bounded,
92 {
93 if self.is_empty() {
94 None
95 } else {
96 match self.start_bound() {
97 Bound::Included(a) => Some(a.clone()),
98 Bound::Excluded(a) => a.succ(),
99 Bound::Unbounded => Some(<T as Bounded>::min()),
100 }
101 }
102 }
103
104 pub fn last(&self) -> Option<T>
106 where
107 T: Clone + Measure + PartialEnum + Bounded,
108 {
109 if self.is_empty() {
110 None
111 } else {
112 match self.end_bound() {
113 Bound::Included(a) => Some(a.clone()),
114 Bound::Excluded(a) => a.pred(),
115 Bound::Unbounded => Some(<T as Bounded>::max()),
116 }
117 }
118 }
119
120 pub fn add<S>(&mut self, other: &S)
121 where
122 T: Clone + Measure + PartialEnum,
123 S: RangeBounds<T>,
124 {
125 self.start = min_bound(self.start_bound(), other.start_bound(), true).cloned();
126 self.end = max_bound(self.end_bound(), other.end_bound(), false).cloned();
127 }
128
129 pub fn intersects<S>(&self, other: &S) -> bool
130 where
131 T: Measure + PartialEnum,
132 S: RangeBounds<T>,
133 {
134 Directed::End(self.end_bound()) >= Directed::Start(other.start_bound())
135 && Directed::End(other.end_bound()) >= Directed::Start(self.start_bound())
136 }
137
138 pub fn intersection(&self, other: &Self) -> Self
139 where
140 T: Clone + Measure + PartialEnum,
141 {
142 Self {
143 start: max_bound(self.start_bound(), other.start_bound(), true).cloned(),
144 end: min_bound(self.end_bound(), other.end_bound(), false).cloned(),
145 }
146 }
147
148 }
180
181impl<T: fmt::Debug> fmt::Debug for AnyRange<T> {
182 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
183 match &self.start {
184 Bound::Included(v) => v.fmt(f)?,
185 Bound::Excluded(v) => write!(f, "{:?}.", v)?,
186 Bound::Unbounded => write!(f, ".")?,
187 }
188
189 match &self.end {
190 Bound::Included(v) => write!(f, "..={:?}", v),
191 Bound::Excluded(v) => write!(f, "..{:?}", v),
192 Bound::Unbounded => write!(f, ".."),
193 }
194 }
195}
196
197impl<'a, T> AnyRange<&'a T> {
198 pub fn ref_is_empty(&self) -> bool
199 where
200 T: PartialEnum + Measure,
201 {
202 is_range_empty(self.start_bound().cloned(), self.end_bound().cloned())
203 }
204}
205
206impl<T, U> PartialEq<AnyRange<U>> for AnyRange<T>
207where
208 T: Measure<U> + PartialOrd<U> + PartialEnum,
209 U: PartialEnum,
210{
211 fn eq(&self, other: &AnyRange<U>) -> bool {
212 direct_bound_partial_eq(self.start_bound(), other.start_bound(), true)
213 && direct_bound_partial_eq(self.end_bound(), other.end_bound(), false)
214 }
215}
216
217impl<T> Eq for AnyRange<T> where T: Measure + PartialEnum + Ord {}
218
219impl<T, U> PartialOrd<AnyRange<U>> for AnyRange<T>
220where
221 T: Measure<U> + PartialOrd<U> + PartialEnum,
222 U: PartialEnum,
223{
224 fn partial_cmp(&self, other: &AnyRange<U>) -> Option<Ordering> {
225 match direct_bound_partial_cmp(self.start_bound(), other.start_bound(), true) {
227 Some(BoundOrdering::Excluded(_)) => Some(Ordering::Less),
228 Some(BoundOrdering::Included(false)) => Some(Ordering::Greater),
229 Some(BoundOrdering::Included(true)) => {
230 match direct_bound_partial_cmp(self.end_bound(), other.end_bound(), false) {
231 Some(BoundOrdering::Excluded(_)) => Some(Ordering::Greater),
232 Some(BoundOrdering::Included(false)) => Some(Ordering::Less),
233 Some(BoundOrdering::Included(true)) => Some(Ordering::Equal),
234 None => None,
235 }
236 }
237 None => None,
238 }
239 }
240}
241
242impl<T> Ord for AnyRange<T>
243where
244 T: Measure + PartialEnum + Ord,
245{
246 fn cmp(&self, other: &Self) -> Ordering {
247 match direct_bound_cmp(self.start_bound(), other.start_bound(), true) {
249 BoundOrdering::Excluded(_) => Ordering::Less,
250 BoundOrdering::Included(false) => Ordering::Greater,
251 BoundOrdering::Included(true) => {
252 match direct_bound_cmp(self.end_bound(), other.end_bound(), false) {
253 BoundOrdering::Excluded(_) => Ordering::Greater,
254 BoundOrdering::Included(false) => Ordering::Less,
255 BoundOrdering::Included(true) => Ordering::Equal,
256 }
257 }
258 }
259 }
260}
261
262impl<T> Hash for AnyRange<T>
263where
264 T: Hash + PartialEnum,
265{
266 fn hash<H: Hasher>(&self, h: &mut H) {
267 Directed::Start(self.start_bound()).hash(h);
268 Directed::End(self.end_bound()).hash(h);
269 }
270}
271
272impl<T: Clone> AnyRange<&T> {
273 pub fn cloned(self) -> AnyRange<T> {
274 AnyRange {
275 start: self.start.cloned(),
276 end: self.end.cloned(),
277 }
278 }
279}
280
281impl<T> RangeBounds<T> for AnyRange<T> {
282 fn start_bound(&self) -> Bound<&T> {
283 match &self.start {
284 Bound::Included(v) => Bound::Included(v),
285 Bound::Excluded(v) => Bound::Excluded(v),
286 Bound::Unbounded => Bound::Unbounded,
287 }
288 }
289
290 fn end_bound(&self) -> Bound<&T> {
291 match &self.end {
292 Bound::Included(v) => Bound::Included(v),
293 Bound::Excluded(v) => Bound::Excluded(v),
294 Bound::Unbounded => Bound::Unbounded,
295 }
296 }
297}
298
299impl<T> From<std::ops::Range<T>> for AnyRange<T> {
300 fn from(value: std::ops::Range<T>) -> Self {
301 Self {
302 start: Bound::Included(value.start),
303 end: Bound::Excluded(value.end),
304 }
305 }
306}
307
308impl<T> From<std::ops::RangeInclusive<T>> for AnyRange<T> {
309 fn from(value: std::ops::RangeInclusive<T>) -> Self {
310 let (start, end) = value.into_inner();
311
312 Self {
313 start: Bound::Included(start),
314 end: Bound::Included(end),
315 }
316 }
317}
318
319impl<T> From<std::ops::RangeFrom<T>> for AnyRange<T> {
320 fn from(value: std::ops::RangeFrom<T>) -> Self {
321 Self {
322 start: Bound::Included(value.start),
323 end: Bound::Unbounded,
324 }
325 }
326}
327
328impl<T> From<std::ops::RangeTo<T>> for AnyRange<T> {
329 fn from(value: std::ops::RangeTo<T>) -> Self {
330 Self {
331 start: Bound::Unbounded,
332 end: Bound::Excluded(value.end),
333 }
334 }
335}
336
337impl<T> From<std::ops::RangeToInclusive<T>> for AnyRange<T> {
338 fn from(value: std::ops::RangeToInclusive<T>) -> Self {
339 Self {
340 start: Bound::Unbounded,
341 end: Bound::Included(value.end),
342 }
343 }
344}
345
346impl<T> From<std::ops::RangeFull> for AnyRange<T> {
347 fn from(_: std::ops::RangeFull) -> Self {
348 Self {
349 start: Bound::Unbounded,
350 end: Bound::Unbounded,
351 }
352 }
353}
354
355#[cfg(test)]
356mod tests {
357 use super::*;
358
359 #[test]
360 fn intersection_test1() {
361 let a: AnyRange<char> = ('A'..='A').into();
362 assert!(a.intersects(&a))
363 }
364
365 #[test]
366 fn intersection_test2() {
367 let a: AnyRange<char> = ('A'..='A').into();
368 let b: AnyRange<char> = ('B'..='B').into();
369 assert!(!a.intersects(&b))
370 }
371}