btree_range_map/range/
any.rs

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	/// Get the first element of the range if there is one.
89	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	/// Get the last element of the range if there is one.
105	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	// pub fn pick_in_intersection<S>(&self, other: &S) -> Option<T>
149	// where
150	// 	T: Clone + Measure + PartialEnum,
151	// 	S: AsRange + RangeBounds<T>,
152	// {
153	// 	if self.intersects(other) {
154	// 		if Directed::End(self.end_bound()) <= Directed::End(other.end_bound()) {
155	// 			if other.is_empty() {
156	// 				None
157	// 			} else {
158	// 				// pick between other.start and self.end
159	// 				Some(match other.start_bound() {
160	// 					Bound::Included(a) => a.clone(),
161	// 					Bound::Excluded(a) => a.succ().unwrap(),
162	// 					Bound::Unbounded => T::MIN,
163	// 				})
164	// 			}
165	// 		} else if self.is_empty() {
166	// 			None
167	// 		} else {
168	// 			// pick between self.start and other.end
169	// 			Some(match self.start_bound() {
170	// 				Bound::Included(a) => a.clone(),
171	// 				Bound::Excluded(a) => a.succ().unwrap(),
172	// 				Bound::Unbounded => T::MIN,
173	// 			})
174	// 		}
175	// 	} else {
176	// 		None
177	// 	}
178	// }
179}
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		// Directed::Start(self.start_bound()).partial_cmp(Directed::Start(other.start_bound()))
226		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		// Directed::Start(self.start_bound()).partial_cmp(Directed::Start(other.start_bound()))
248		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}