1use crate::helpers::{LeftBound, RightBound};
4use crate::impls::Item;
5use crate::{Interval, IntervalType, Portion};
6use std::ops::{BitAnd, BitOr};
7
8pub trait Operations: Sized {
10 type Output;
12
13 fn empty(&self) -> bool {
15 true
16 }
17
18 fn atomic(&self) -> bool {
20 true
21 }
22
23 fn intersection(self, _other: Self::Output) -> Self::Output {
25 unimplemented!()
26 }
27
28 fn union(self, _other: Self::Output) -> Self::Output {
30 unimplemented!()
31 }
32}
33
34impl<T: Item> Operations for Interval<T> {
35 type Output = Self;
36
37 fn empty(&self) -> bool {
38 use IntervalType::*;
39 match self.itype {
40 Open => self.lower >= self.upper,
41 Closed => self.lower > self.upper,
42 Empty => true,
43 Singleton => false,
44 OpenClosed => self.lower >= self.upper,
45 ClosedOpen => self.lower >= self.upper,
46 }
47 }
48
49 fn intersection(self, other: Self::Output) -> Self::Output {
50 self & other
51 }
52
53 fn union(self, other: Self::Output) -> Self::Output {
54 self | other
55 }
56}
57
58impl<T: Item> BitAnd for Interval<T> {
60 type Output = Self;
61
62 fn bitand(self, rhs: Self) -> Self::Output {
63 if self.empty() || rhs.empty() {
65 return Portion::empty();
66 }
67
68 if self.singleton() {
70 if rhs.contains(self.lower()) {
71 return self;
72 } else {
73 return Portion::empty();
74 }
75 }
76
77 if rhs.singleton() {
78 if self.contains(rhs.lower.unwrap()) {
79 return rhs;
80 } else {
81 return Portion::empty();
82 }
83 }
84
85 if self.upper < rhs.lower {
87 return Portion::empty();
88 }
89
90 let left_bound = self.get_left_bound(&rhs);
92 let right_bound = self.get_right_bound(&rhs);
93
94 match left_bound {
95 LeftBound::Open(lower) => match right_bound {
96 RightBound::Open(upper) => Portion::open(lower, upper),
97 RightBound::Closed(upper) => Portion::openclosed(lower, upper),
98 RightBound::None => Portion::empty(),
99 },
100 LeftBound::Closed(lower) => match right_bound {
101 RightBound::Open(upper) => Portion::closedopen(lower, upper),
102 RightBound::Closed(upper) => Portion::closed(lower, upper),
103 RightBound::None => Portion::empty(),
104 },
105 LeftBound::None => Portion::empty(),
106 }
107 }
108}
109
110impl<T: Item> BitOr for Interval<T> {
112 type Output = Self;
113
114 fn bitor(self, rhs: Interval<T>) -> Self::Output {
115 if self.empty() {
116 return rhs;
117 }
118
119 if rhs.empty() {
120 return self;
121 }
122
123 #[allow(clippy::suspicious_operation_groupings)]
125 if !self.singleton() && !rhs.singleton() && self.upper < rhs.lower {
126 return Portion::empty();
127 }
128
129 let left_val = self.get_lowest_val(&rhs);
130 let right_val = self.get_highest_val(&rhs);
131
132 match left_val {
133 LeftBound::Closed(lower) => match right_val {
134 RightBound::Closed(upper) => Portion::closed(lower, upper),
135 RightBound::Open(upper) => Portion::closedopen(lower, upper),
136 RightBound::None => unreachable!(),
137 },
138 LeftBound::Open(lower) => match right_val {
139 RightBound::Closed(upper) => Portion::openclosed(lower, upper),
140 RightBound::Open(upper) => Portion::open(lower, upper),
141 RightBound::None => unreachable!(),
142 },
143 LeftBound::None => unreachable!(),
144 }
145 }
146}