1use crate::{
2 bound_type::{Left, Right},
3 traits::{BoundaryOf, Flip, IntoGeneral},
4 Bound, BoundType, Exclusive, Inclusive,
5};
6
7#[derive(Debug, Clone, Copy)]
8pub struct HalfBounded<T, B, LR>(pub(crate) Bound<T, B>, std::marker::PhantomData<LR>);
9
10pub type LeftBounded<T, B> = HalfBounded<T, B, Left>;
11pub type RightBounded<T, B> = HalfBounded<T, B, Right>;
12
13impl<T, B, LR> std::ops::Deref for HalfBounded<T, B, LR> {
14 type Target = Bound<T, B>;
15 fn deref(&self) -> &Self::Target {
16 &self.0
17 }
18}
19impl<T, B, LR> std::ops::DerefMut for HalfBounded<T, B, LR> {
20 fn deref_mut(&mut self) -> &mut Self::Target {
21 &mut self.0
22 }
23}
24
25mod ordering {
26 use super::HalfBounded;
27 use crate::traits::BoundaryOf;
28
29 impl<T: PartialEq, B: PartialEq, LR> PartialEq for HalfBounded<T, B, LR> {
30 fn eq(&self, other: &Self) -> bool {
31 self.0 == other.0
32 }
33 }
34 impl<T: Eq, B: Eq, LR> Eq for HalfBounded<T, B, LR> {}
35
36 impl<T: PartialOrd, B: BoundaryOf<LR>, LR> HalfBounded<T, B, LR> {
37 fn ordering_key(&self) -> (&T, B::Ordered) {
38 (&self.limit, self.bound_type.into_ordered())
39 }
40 }
41 impl<T: PartialOrd, B: BoundaryOf<LR>, LR> PartialOrd for HalfBounded<T, B, LR> {
42 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
43 self.ordering_key().partial_cmp(&other.ordering_key())
44 }
45 }
46}
47
48impl<T, B, LR> From<Bound<T, B>> for HalfBounded<T, B, LR> {
49 fn from(b: Bound<T, B>) -> Self {
50 HalfBounded(b, std::marker::PhantomData)
51 }
52}
53
54impl<T, B: IntoGeneral, LR> IntoGeneral for HalfBounded<T, B, LR> {
55 type General = HalfBounded<T, B::General, LR>;
56 fn into_general(self) -> Self::General {
57 HalfBounded(self.0.into_general(), std::marker::PhantomData)
58 }
59}
60
61impl<T, B: Flip, LR: Flip> Flip for HalfBounded<T, B, LR> {
62 type Flip = HalfBounded<T, B::Flip, LR::Flip>;
63 fn flip(self) -> Self::Flip {
64 HalfBounded(self.0.flip(), std::marker::PhantomData)
65 }
66}
67
68impl<T, B, LR> HalfBounded<T, B, LR> {
69 pub fn cast<U: From<T>>(self) -> HalfBounded<U, B, LR> {
70 self.0.cast().into()
71 }
72}
73impl<T: num::NumCast, B, LR> HalfBounded<T, B, LR> {
74 pub fn try_cast<U: num::NumCast>(self) -> Option<HalfBounded<U, B, LR>> {
75 self.0.try_cast().map(Into::into)
76 }
77}
78
79pub(crate) fn partial_min<T: PartialOrd>(a: T, b: T) -> T {
80 if a < b {
81 a
82 } else {
83 b
84 }
85}
86pub(crate) fn partial_max<T: PartialOrd>(a: T, b: T) -> T {
87 if a > b {
88 a
89 } else {
90 b
91 }
92}
93
94impl<T: PartialOrd, B: BoundaryOf<LR>, LR> HalfBounded<T, B, LR> {
95 fn min<'a>(&'a self, other: &'a Self) -> &'a Self {
96 partial_min(self, other)
97 }
98 fn max<'a>(&'a self, other: &'a Self) -> &'a Self {
99 partial_max(self, other)
100 }
101}
102
103impl<T: PartialOrd, B: BoundaryOf<Left>> LeftBounded<T, B> {
104 pub fn includes(&self, other: &Self) -> bool {
105 self.limit <= other.limit
106 }
107 pub fn contains(&self, t: &T) -> bool {
108 self.bound_type.less(&self.limit, t)
109 }
110 pub fn intersection<'a>(&'a self, other: &'a Self) -> &'a Self {
111 self.max(other)
112 }
113 pub fn union<'a>(&'a self, other: &'a Self) -> &'a Self {
114 self.min(other)
115 }
116
117 pub fn hull(self, t: T) -> Self {
118 Bound {
119 limit: partial_min(self.0.limit, t),
120 bound_type: self.0.bound_type,
121 }
122 .into()
123 }
124
125 pub fn dilate(self, delta: T) -> Self
126 where
127 T: std::ops::Sub<Output = T>,
128 {
129 Bound {
130 limit: self.0.limit - delta,
131 bound_type: self.0.bound_type,
132 }
133 .into()
134 }
135
136 pub fn inf(&self) -> &T {
137 &self.limit
138 }
139
140 pub fn closure(self) -> LeftBounded<T, Inclusive> {
141 Bound {
142 limit: self.0.limit,
143 bound_type: Inclusive,
144 }
145 .into()
146 }
147
148 pub fn interior(self) -> LeftBounded<T, Exclusive> {
149 Bound {
150 limit: self.0.limit,
151 bound_type: Exclusive,
152 }
153 .into()
154 }
155
156 pub fn step_by(&self, step: T) -> impl Iterator<Item = T>
157 where
158 T: Clone,
159 for<'a> T: std::ops::AddAssign<&'a T>,
160 {
161 let mut t = self.limit.clone();
162 if self.bound_type == BoundType::Exclusive {
163 t += &step;
164 };
165 std::iter::from_fn(move || {
166 let r = t.clone();
167 t += &step;
168 Some(r)
169 })
170 }
171}
172
173impl<T: PartialOrd, B: BoundaryOf<Right>> RightBounded<T, B> {
174 pub fn includes(&self, other: &Self) -> bool {
175 other.limit <= self.limit
176 }
177 pub fn contains(&self, t: &T) -> bool {
178 self.bound_type.less(t, &self.limit)
179 }
180 pub fn intersection<'a>(&'a self, other: &'a Self) -> &'a Self {
181 self.min(other)
182 }
183 pub fn union<'a>(&'a self, other: &'a Self) -> &'a Self {
184 self.max(other)
185 }
186
187 pub fn hull(self, t: T) -> Self {
188 Bound {
189 limit: partial_max(self.0.limit, t),
190 bound_type: self.0.bound_type,
191 }
192 .into()
193 }
194
195 pub fn dilate(self, delta: T) -> Self
196 where
197 T: std::ops::Add<Output = T>,
198 {
199 Bound {
200 limit: self.0.limit + delta,
201 bound_type: self.0.bound_type,
202 }
203 .into()
204 }
205
206 pub fn sup(&self) -> &T {
207 &self.limit
208 }
209
210 pub fn closure(self) -> RightBounded<T, Inclusive> {
211 Bound {
212 limit: self.0.limit,
213 bound_type: Inclusive,
214 }
215 .into()
216 }
217
218 pub fn interior(self) -> RightBounded<T, Exclusive> {
219 Bound {
220 limit: self.0.limit,
221 bound_type: Exclusive,
222 }
223 .into()
224 }
225
226 pub fn step_rev_by(&self, step: T) -> impl Iterator<Item = T>
227 where
228 T: Clone,
229 for<'a> T: std::ops::SubAssign<&'a T>,
230 {
231 let mut t = self.limit.clone();
232 if self.bound_type == BoundType::Exclusive {
233 t -= &step;
234 };
235 std::iter::from_fn(move || {
236 let r = t.clone();
237 t -= &step;
238 Some(r)
239 })
240 }
241}