1use crate::bound_pair::BoundPair;
2use itertools::Either;
3use std::cmp::Ordering;
4
5#[cfg(not(feature = "serde"))]
6mod without_serde {
7 use crate::bound_pair::BoundPair;
8 #[derive(Debug, Copy, Clone, PartialEq)]
36 pub enum Interval<T> {
37 Closed { bound_pair: BoundPair<T> },
38 Open { bound_pair: BoundPair<T> },
39 LeftHalfOpen { bound_pair: BoundPair<T> },
40 RightHalfOpen { bound_pair: BoundPair<T> },
41 UnboundedClosedRight { right: T },
42 UnboundedOpenRight { right: T },
43 UnboundedClosedLeft { left: T },
44 UnboundedOpenLeft { left: T },
45 Singleton { at: T },
46 Unbounded,
47 Empty,
48 }
49}
50
51#[cfg(feature = "serde")]
52mod with_serde {
53 use serde::{Deserialize, Serialize};
54
55 use crate::bound_pair::BoundPair;
56 #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
84 pub enum Interval<T> {
85 Closed { bound_pair: BoundPair<T> },
86 Open { bound_pair: BoundPair<T> },
87 LeftHalfOpen { bound_pair: BoundPair<T> },
88 RightHalfOpen { bound_pair: BoundPair<T> },
89 UnboundedClosedRight { right: T },
90 UnboundedOpenRight { right: T },
91 UnboundedClosedLeft { left: T },
92 UnboundedOpenLeft { left: T },
93 Singleton { at: T },
94 Unbounded,
95 Empty,
96 }
97}
98
99#[cfg(feature = "serde")]
100pub use with_serde::Interval;
101#[cfg(not(feature = "serde"))]
102pub use without_serde::Interval;
103
104enum Bound<T> {
106 None,
107 Unbounded,
108 Open(T),
109 Closed(T),
110}
111
112type TwoIntervalIter<T> =
113 std::iter::Chain<std::iter::Once<Interval<T>>, std::iter::Once<Interval<T>>>;
114type OneIntervalIter<T> = std::iter::Once<Interval<T>>;
115
116impl<T> Interval<T>
117where
118 T: Copy,
119 T: std::cmp::PartialOrd,
120{
121 pub fn contains(&self, other: &Interval<T>) -> bool {
162 let self_right_bound = self.right_bound();
163 let other_right_bound = other.right_bound();
164 let self_left_bound = self.left_bound();
165 let other_left_bound = other.left_bound();
166
167 let left_contained = match (self_left_bound, other_left_bound) {
168 (Bound::None, _) => false,
170 (_, Bound::None) => true,
172 (Bound::Unbounded, _) => true,
174 (_, Bound::Unbounded) => false,
177 (Bound::Closed(ref self_val), Bound::Closed(ref other_val))
178 | (Bound::Closed(ref self_val), Bound::Open(ref other_val))
179 | (Bound::Open(ref self_val), Bound::Open(ref other_val)) => self_val <= other_val,
180 (Bound::Open(ref self_val), Bound::Closed(ref other_val)) => self_val < other_val,
181 };
182
183 let right_contained = match (self_right_bound, other_right_bound) {
184 (Bound::None, _) => false,
186 (_, Bound::None) => false,
187 (Bound::Unbounded, _) => true,
189 (_, Bound::Unbounded) => false,
192 (Bound::Closed(ref self_val), Bound::Closed(ref other_val))
193 | (Bound::Closed(ref self_val), Bound::Open(ref other_val))
194 | (Bound::Open(ref self_val), Bound::Open(ref other_val)) => self_val >= other_val,
195 (Bound::Open(ref self_val), Bound::Closed(ref other_val)) => self_val > other_val,
196 };
197
198 left_contained && right_contained
199 }
200
201 pub fn intersect(&self, other: &Interval<T>) -> Interval<T> {
229 let left_cmp_partial = self.left_partial_cmp(other);
230 let right_cmp_partial = self.right_partial_cmp(other);
231 if left_cmp_partial.is_none() || right_cmp_partial.is_none() {
232 return Interval::Empty;
233 }
234
235 let left_bound = if left_cmp_partial != Some(Ordering::Less) {
236 self.left_bound()
237 } else {
238 other.left_bound()
239 };
240 let right_bound = if right_cmp_partial != Some(Ordering::Greater) {
241 self.right_bound()
242 } else {
243 other.right_bound()
244 };
245
246 match (left_bound, right_bound) {
247 (Bound::None, _) => Interval::Empty,
248 (_, Bound::None) => Interval::Empty,
249 (Bound::Closed(left), Bound::Closed(right)) => {
250 if left > right {
251 Interval::Empty
252 } else if left == right {
253 Interval::Singleton { at: left }
254 } else {
255 Interval::Closed {
256 bound_pair: BoundPair { left, right },
257 }
258 }
259 }
260 (Bound::Open(left), Bound::Open(right)) => {
261 if left >= right {
262 Interval::Empty
263 } else {
264 Interval::Open {
265 bound_pair: BoundPair { left, right },
266 }
267 }
268 }
269 (Bound::Open(left), Bound::Closed(right)) => {
270 if left >= right {
271 Interval::Empty
272 } else {
273 Interval::LeftHalfOpen {
274 bound_pair: BoundPair { left, right },
275 }
276 }
277 }
278 (Bound::Closed(left), Bound::Open(right)) => {
279 if left >= right {
280 Interval::Empty
281 } else {
282 Interval::RightHalfOpen {
283 bound_pair: BoundPair { left, right },
284 }
285 }
286 }
287 (Bound::Unbounded, Bound::Closed(right)) => Interval::UnboundedClosedRight { right },
288 (Bound::Unbounded, Bound::Open(right)) => Interval::UnboundedOpenRight { right },
289 (Bound::Closed(left), Bound::Unbounded) => Interval::UnboundedClosedLeft { left },
290 (Bound::Open(left), Bound::Unbounded) => Interval::UnboundedOpenLeft { left },
291 (Bound::Unbounded, Bound::Unbounded) => Interval::Unbounded,
292 }
293 }
294
295 fn left_bound(&self) -> Bound<T> {
296 match self {
297 Interval::Empty => Bound::None,
298 Interval::Singleton { ref at } => Bound::Closed(*at),
299 Interval::Unbounded
301 | Interval::UnboundedClosedRight { .. }
302 | Interval::UnboundedOpenRight { .. } => Bound::Unbounded,
303 Interval::Closed {
305 bound_pair: BoundPair { ref left, .. },
306 }
307 | Interval::RightHalfOpen {
308 bound_pair: BoundPair { ref left, .. },
309 }
310 | Interval::UnboundedClosedLeft { ref left, .. } => Bound::Closed(*left),
311 Interval::Open {
313 bound_pair: BoundPair { ref left, .. },
314 }
315 | Interval::LeftHalfOpen {
316 bound_pair: BoundPair { ref left, .. },
317 }
318 | Interval::UnboundedOpenLeft { ref left, .. } => Bound::Open(*left),
319 }
320 }
321
322 fn right_bound(&self) -> Bound<T> {
323 match self {
324 Interval::Empty => Bound::None,
325 Interval::Singleton { ref at } => Bound::Closed(*at),
326 Interval::Unbounded
328 | Interval::UnboundedClosedLeft { .. }
329 | Interval::UnboundedOpenLeft { .. } => Bound::Unbounded,
330 Interval::Closed {
332 bound_pair: BoundPair { ref right, .. },
333 }
334 | Interval::LeftHalfOpen {
335 bound_pair: BoundPair { ref right, .. },
336 }
337 | Interval::UnboundedClosedRight { ref right, .. } => Bound::Closed(*right),
338 Interval::Open {
340 bound_pair: BoundPair { ref right, .. },
341 }
342 | Interval::RightHalfOpen {
343 bound_pair: BoundPair { ref right, .. },
344 }
345 | Interval::UnboundedOpenRight { ref right, .. } => Bound::Open(*right),
346 }
347 }
348
349 pub fn left_partial_cmp(&self, other: &Interval<T>) -> Option<Ordering> {
378 let self_left_bound = self.left_bound();
379 let other_left_bound = other.left_bound();
380
381 match (self_left_bound, other_left_bound) {
382 (Bound::None, _) => None,
383 (_, Bound::None) => None,
384 (Bound::Unbounded, Bound::Unbounded) => Some(Ordering::Equal),
386 (Bound::Unbounded, _) => Some(Ordering::Less),
387 (_, Bound::Unbounded) => Some(Ordering::Greater),
388 (Bound::Closed(self_val), Bound::Closed(other_val)) => {
390 if self_val < other_val {
391 Some(Ordering::Less)
392 } else if self_val > other_val {
393 Some(Ordering::Greater)
394 } else {
395 Some(Ordering::Equal)
396 }
397 }
398 (Bound::Closed(self_val), Bound::Open(other_val)) => {
399 if self_val <= other_val {
400 Some(Ordering::Less)
401 } else {
402 Some(Ordering::Greater)
403 }
404 }
405 (Bound::Open(self_val), Bound::Closed(other_val)) => {
407 if self_val < other_val {
408 Some(Ordering::Less)
409 } else {
410 Some(Ordering::Greater)
411 }
412 }
413 (Bound::Open(self_val), Bound::Open(other_val)) => {
414 if self_val < other_val {
415 Some(Ordering::Less)
416 } else if self_val > other_val {
417 Some(Ordering::Greater)
418 } else {
419 Some(Ordering::Equal)
420 }
421 }
422 }
423 }
424
425 pub fn right_partial_cmp(&self, other: &Interval<T>) -> Option<Ordering> {
454 let self_right_bound = self.right_bound();
455 let other_right_bound = other.right_bound();
456
457 match (self_right_bound, other_right_bound) {
458 (Bound::None, _) => None,
459 (_, Bound::None) => None,
460 (Bound::Unbounded, Bound::Unbounded) => Some(Ordering::Equal),
462 (Bound::Unbounded, _) => Some(Ordering::Greater),
463 (_, Bound::Unbounded) => Some(Ordering::Less),
464 (Bound::Closed(self_val), Bound::Closed(other_val)) => {
466 if self_val < other_val {
467 Some(Ordering::Less)
468 } else if self_val > other_val {
469 Some(Ordering::Greater)
470 } else {
471 Some(Ordering::Equal)
472 }
473 }
474 (Bound::Closed(self_val), Bound::Open(other_val)) => {
475 if self_val < other_val {
476 Some(Ordering::Less)
477 } else {
478 Some(Ordering::Greater)
479 }
480 }
481 (Bound::Open(self_val), Bound::Closed(other_val)) => {
483 if self_val <= other_val {
484 Some(Ordering::Less)
485 } else {
486 Some(Ordering::Greater)
487 }
488 }
489 (Bound::Open(self_val), Bound::Open(other_val)) => {
490 if self_val < other_val {
491 Some(Ordering::Less)
492 } else if self_val > other_val {
493 Some(Ordering::Greater)
494 } else {
495 Some(Ordering::Equal)
496 }
497 }
498 }
499 }
500
501 pub fn width(&self) -> Option<<T as std::ops::Sub>::Output>
526 where
527 T: std::ops::Sub,
528 {
529 let self_left_bound = self.left_bound();
530 let self_right_bound = self.right_bound();
531
532 match (self_left_bound, self_right_bound) {
533 (Bound::None, _) => None,
534 (_, Bound::None) => None,
535 (Bound::Unbounded, _) => None,
536 (_, Bound::Unbounded) => None,
537 (Bound::Closed(left), Bound::Closed(right)) => Some(right - left),
538 (Bound::Closed(left), Bound::Open(right)) => Some(right - left),
539 (Bound::Open(left), Bound::Closed(right)) => Some(right - left),
540 (Bound::Open(left), Bound::Open(right)) => Some(right - left),
541 }
542 }
543
544 pub fn complement(&self) -> itertools::Either<OneIntervalIter<T>, TwoIntervalIter<T>> {
578 match self {
579 Interval::Closed { bound_pair } => {
580 let BoundPair { left, right } = *bound_pair;
581 Either::Right(
582 std::iter::once(Interval::UnboundedOpenRight { right: left })
583 .chain(std::iter::once(Interval::UnboundedOpenLeft { left: right })),
584 )
585 }
586 Interval::Open { bound_pair } => {
587 let BoundPair { left, right } = *bound_pair;
588 Either::Right(
589 std::iter::once(Interval::UnboundedClosedRight { right: left }).chain(
590 std::iter::once(Interval::UnboundedClosedLeft { left: right }),
591 ),
592 )
593 }
594 Interval::LeftHalfOpen { bound_pair } => {
595 let BoundPair { left, right } = *bound_pair;
596 Either::Right(
597 std::iter::once(Interval::UnboundedClosedRight { right: left })
598 .chain(std::iter::once(Interval::UnboundedOpenLeft { left: right })),
599 )
600 }
601 Interval::RightHalfOpen { bound_pair } => {
602 let BoundPair { left, right } = *bound_pair;
603 Either::Right(
604 std::iter::once(Interval::UnboundedOpenRight { right: left }).chain(
605 std::iter::once(Interval::UnboundedClosedLeft { left: right }),
606 ),
607 )
608 }
609 Interval::UnboundedClosedRight { right } => {
610 Either::Left(std::iter::once(Interval::UnboundedOpenLeft {
611 left: *right,
612 }))
613 }
614 Interval::UnboundedOpenRight { right } => {
615 Either::Left(std::iter::once(Interval::UnboundedClosedLeft {
616 left: *right,
617 }))
618 }
619 Interval::UnboundedClosedLeft { left } => {
620 Either::Left(std::iter::once(Interval::UnboundedOpenRight {
621 right: *left,
622 }))
623 }
624 Interval::UnboundedOpenLeft { left } => {
625 Either::Left(std::iter::once(Interval::UnboundedClosedRight {
626 right: *left,
627 }))
628 }
629 Interval::Singleton { at } => Either::Right(
630 std::iter::once(Interval::UnboundedOpenRight { right: *at })
631 .chain(std::iter::once(Interval::UnboundedOpenLeft { left: *at })),
632 ),
633 Interval::Unbounded => Either::Left(std::iter::once(Interval::Empty)),
634 Interval::Empty => Either::Left(std::iter::once(Interval::Unbounded)),
635 }
636 }
637}
638
639impl<T> std::fmt::Display for Interval<T>
661where
662 T: std::fmt::Debug,
663{
664 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
665 match self {
666 Interval::Closed {
667 bound_pair:
668 BoundPair {
669 ref left,
670 ref right,
671 },
672 } => write!(f, "[{:?}..{:?}]", left, right),
673 Interval::Open {
674 bound_pair:
675 BoundPair {
676 ref left,
677 ref right,
678 },
679 } => write!(f, "({:?}..{:?})", left, right),
680 Interval::LeftHalfOpen {
681 bound_pair:
682 BoundPair {
683 ref left,
684 ref right,
685 },
686 } => write!(f, "({:?}..{:?}]", left, right),
687 Interval::RightHalfOpen {
688 bound_pair:
689 BoundPair {
690 ref left,
691 ref right,
692 },
693 } => write!(f, "[{:?}..{:?})", left, right),
694 Interval::UnboundedClosedRight { ref right } => write!(f, "(←..{:?}]", right),
695 Interval::UnboundedOpenRight { ref right } => write!(f, "(←..{:?})", right),
696 Interval::UnboundedClosedLeft { ref left } => write!(f, "[{:?}..→)", left),
697 Interval::UnboundedOpenLeft { ref left } => write!(f, "({:?}..→)", left),
698 Interval::Singleton { ref at } => write!(f, "[{:?}]", at),
699 Interval::Unbounded => write!(f, "(←..→)"),
700 Interval::Empty => write!(f, "Empty"),
701 }
702 }
703}
704
705#[cfg(test)]
706mod tests {
707 use crate::bound_pair::BoundPair;
708 use crate::interval::Interval;
709 use itertools::Either;
710 use quickcheck::Arbitrary;
711 use quickcheck::Gen;
712 use quickcheck::TestResult;
713 use quickcheck_macros::quickcheck;
714
715 impl<T> Arbitrary for Interval<T>
716 where
717 T: Arbitrary + Copy + Clone + PartialOrd + Send + 'static,
718 {
719 fn arbitrary(g: &mut Gen) -> Interval<T> {
720 const VARIANT_COUNT: usize = 12;
721 let variant_idx = g.size() % VARIANT_COUNT;
722
723 match variant_idx {
724 0 => {
725 let bound_pair = loop {
726 let left = T::arbitrary(g);
727 let right = T::arbitrary(g);
728 if let Some(bp) = BoundPair::new(left, right) {
729 break bp;
730 }
731 };
732 Interval::Closed { bound_pair }
733 }
734 1 => {
735 let bound_pair = loop {
736 let left = T::arbitrary(g);
737 let right = T::arbitrary(g);
738 if let Some(bp) = BoundPair::new(left, right) {
739 break bp;
740 }
741 };
742 Interval::Open { bound_pair }
743 }
744 2 => {
745 let bound_pair = loop {
746 let left = T::arbitrary(g);
747 let right = T::arbitrary(g);
748 if let Some(bp) = BoundPair::new(left, right) {
749 break bp;
750 }
751 };
752 Interval::LeftHalfOpen { bound_pair }
753 }
754 3 => {
755 let bound_pair = loop {
756 let left = T::arbitrary(g);
757 let right = T::arbitrary(g);
758 if let Some(bp) = BoundPair::new(left, right) {
759 break bp;
760 }
761 };
762 Interval::LeftHalfOpen { bound_pair }
763 }
764 4 => {
765 let bound_pair = loop {
766 let left = T::arbitrary(g);
767 let right = T::arbitrary(g);
768 if let Some(bp) = BoundPair::new(left, right) {
769 break bp;
770 }
771 };
772 Interval::RightHalfOpen { bound_pair }
773 }
774 5 => Interval::UnboundedClosedRight {
775 right: T::arbitrary(g),
776 },
777 6 => Interval::UnboundedOpenRight {
778 right: T::arbitrary(g),
779 },
780 7 => Interval::UnboundedClosedLeft {
781 left: T::arbitrary(g),
782 },
783 8 => Interval::UnboundedOpenLeft {
784 left: T::arbitrary(g),
785 },
786 9 => Interval::Singleton {
787 at: T::arbitrary(g),
788 },
789 10 => Interval::Unbounded,
790 11 => Interval::Empty,
791 _ => unreachable!("variant_idx is always < VARIANT_COUNT"),
792 }
793 }
794
795 }
803
804 #[test]
805 fn test_bounded_complements() {
806 let bp = BoundPair::new(1, 5).unwrap();
807 let mut it = Interval::Closed { bound_pair: bp }.complement();
808 assert_eq!(it.next(), Some(Interval::UnboundedOpenRight { right: 1 }));
809 assert_eq!(it.next(), Some(Interval::UnboundedOpenLeft { left: 5 }));
810 assert_eq!(it.next(), None);
811
812 it = Interval::Open { bound_pair: bp }.complement();
813 assert_eq!(it.next(), Some(Interval::UnboundedClosedRight { right: 1 }));
814 assert_eq!(it.next(), Some(Interval::UnboundedClosedLeft { left: 5 }));
815 assert_eq!(it.next(), None);
816
817 it = Interval::LeftHalfOpen { bound_pair: bp }.complement();
818 assert_eq!(it.next(), Some(Interval::UnboundedClosedRight { right: 1 }));
819 assert_eq!(it.next(), Some(Interval::UnboundedOpenLeft { left: 5 }));
820 assert_eq!(it.next(), None);
821
822 it = Interval::RightHalfOpen { bound_pair: bp }.complement();
823 assert_eq!(it.next(), Some(Interval::UnboundedOpenRight { right: 1 }));
824 assert_eq!(it.next(), Some(Interval::UnboundedClosedLeft { left: 5 }));
825 assert_eq!(it.next(), None);
826 }
827
828 #[test]
829 fn test_unbounded_complements() {
830 let mut it = Interval::UnboundedClosedRight { right: 5 }.complement();
831 assert_eq!(it.next(), Some(Interval::UnboundedOpenLeft { left: 5 }));
832 assert_eq!(it.next(), None);
833
834 it = Interval::UnboundedOpenRight { right: 5 }.complement();
835 assert_eq!(it.next(), Some(Interval::UnboundedClosedLeft { left: 5 }));
836 assert_eq!(it.next(), None);
837
838 it = Interval::UnboundedClosedLeft { left: 1 }.complement();
839 assert_eq!(it.next(), Some(Interval::UnboundedOpenRight { right: 1 }));
840 assert_eq!(it.next(), None);
841
842 it = Interval::UnboundedOpenLeft { left: 1 }.complement();
843 assert_eq!(it.next(), Some(Interval::UnboundedClosedRight { right: 1 }));
844 assert_eq!(it.next(), None);
845
846 let mut it = Interval::Singleton { at: 2.0 }.complement();
847 assert_eq!(it.next(), Some(Interval::UnboundedOpenRight { right: 2.0 }));
848 assert_eq!(it.next(), Some(Interval::UnboundedOpenLeft { left: 2.0 }));
849 assert_eq!(it.next(), None);
850
851 it = Interval::Unbounded.complement();
852 assert_eq!(it.next(), Some(Interval::Empty));
853 assert_eq!(it.next(), None);
854
855 it = Interval::Empty.complement();
856 assert_eq!(it.next(), Some(Interval::Unbounded));
857 assert_eq!(it.next(), None);
858 }
859
860 #[test]
861 fn interval_display() {
862 let bp = BoundPair::new(1, 5).ok_or("invalid BoundPair").unwrap();
863
864 assert_eq!(format!("{}", Interval::Closed { bound_pair: bp }), "[1..5]");
865 assert_eq!(format!("{}", Interval::Open { bound_pair: bp }), "(1..5)");
866 assert_eq!(
867 format!("{}", Interval::LeftHalfOpen { bound_pair: bp }),
868 "(1..5]"
869 );
870 assert_eq!(
871 format!("{}", Interval::RightHalfOpen { bound_pair: bp }),
872 "[1..5)"
873 );
874 assert_eq!(
875 format!("{}", Interval::UnboundedClosedRight { right: 5 }),
876 "(←..5]"
877 );
878 assert_eq!(
879 format!("{}", Interval::UnboundedOpenRight { right: 5 }),
880 "(←..5)"
881 );
882 assert_eq!(
883 format!("{}", Interval::UnboundedClosedLeft { left: 1 }),
884 "[1..→)"
885 );
886 assert_eq!(
887 format!("{}", Interval::UnboundedOpenLeft { left: 1 }),
888 "(1..→)"
889 );
890 assert_eq!(format!("{}", Interval::Singleton { at: 3.0 }), "[3.0]");
891 assert_eq!(format!("{}", Interval::Unbounded::<u32> {}), "(←..→)");
892 assert_eq!(format!("{}", Interval::Empty::<u32> {}), "Empty");
893 }
894
895 #[quickcheck]
896 fn intersect_strictly_shrinks_u32(l1: u32, l2: u32, r1: u32, r2: u32) -> TestResult {
897 if let (Some(bp1), Some(bp2)) = (BoundPair::new(l1, r1), BoundPair::new(l2, r2)) {
898 let i1 = Interval::LeftHalfOpen { bound_pair: bp1 };
899 let i2 = Interval::LeftHalfOpen { bound_pair: bp2 };
900 let intersection = i1.intersect(&i2);
901 TestResult::from_bool(
902 !(intersection.width() > i1.width() || intersection.width() > i2.width()),
903 )
904 } else {
905 TestResult::discard()
907 }
908 }
909
910 #[quickcheck]
911 fn intersect_strictly_shrinks_f32(l1: f32, l2: f32, r1: f32, r2: f32) -> TestResult {
912 if let (Some(bp1), Some(bp2)) = (BoundPair::new(l1, r1), BoundPair::new(l2, r2)) {
913 let i1 = Interval::LeftHalfOpen { bound_pair: bp1 };
914 let i2 = Interval::LeftHalfOpen { bound_pair: bp2 };
915 let intersection = i1.intersect(&i2);
916 TestResult::from_bool(
917 !(intersection.width() > i1.width() || intersection.width() > i2.width()),
918 )
919 } else {
920 TestResult::discard()
922 }
923 }
924
925 #[quickcheck]
926 fn complement_symmetric_u32(i: Interval<u32>) -> TestResult {
927 let double_complement = match i.complement() {
928 Either::Left(mut interval) => interval.next().unwrap().complement().next().unwrap(),
929 Either::Right(mut intervals) => {
930 let [i1, i2] = [intervals.next().unwrap(), intervals.next().unwrap()];
931 i1.complement()
932 .next()
933 .unwrap()
934 .intersect(&i2.complement().next().unwrap())
935 }
936 };
937
938 TestResult::from_bool(double_complement == i)
939 }
940}