inter_val/
half.rs

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}