1use std::ops::{self, RangeToInclusive};
2
3use num_traits::{One, SaturatingAdd, Zero};
4
5#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
6pub struct OpenRange<Idx> {
7 pub start: Idx,
8 pub end: Option<Idx>,
9}
10
11pub trait PartialRange<Idx: Clone + Ord = usize> {
12 #[must_use]
13 fn start(&self) -> Idx;
14
15 #[must_use]
16 fn end(&self) -> Option<Idx>;
17
18 #[inline]
19 #[must_use]
20 fn clamp(&self, start: impl Into<Idx>, end: impl Into<Idx>) -> ops::Range<Idx> {
21 let lhs_start = start.into();
22 let lhs_end = end.into();
23 let lhs = lhs_start..lhs_end.clone();
24
25 let rhs_start = self.start();
26 let rhs_end = self.end().unwrap_or(lhs_end);
27 let rhs = rhs_start..rhs_end;
28
29 Range::intersection(&lhs, &rhs)
30 }
31
32 #[inline]
33 #[must_use]
34 fn clamp_left(&self, start: impl Into<Idx>) -> OpenRange<Idx> {
35 OpenRange {
36 start: self.start().max(start.into()),
37 end: self.end(),
38 }
39 }
40
41 #[inline]
42 #[must_use]
43 fn clamp_right(&self, end: impl Into<Idx>) -> ops::Range<Idx> {
44 let end = match self.end() {
45 Some(rhs_end) => end.into().min(rhs_end),
46 None => end.into(),
47 };
48
49 let start = self.start().min(end.clone());
50
51 start..end
52 }
53
54 #[inline]
55 #[must_use]
56 fn intersection<T, R>(&self, other: R) -> OpenRange<Idx>
57 where
58 T: Clone + Ord + Into<Idx>,
59 R: PartialRange<T>,
60 {
61 other.end().map_or_else(
62 || self.clamp_left(other.start()),
63 |end| self.clamp(other.start(), end).to_open_range(),
64 )
65 }
66}
67
68impl<Idx: Clone + Ord> PartialRange<Idx> for OpenRange<Idx> {
69 #[inline]
70 fn start(&self) -> Idx {
71 self.start.clone()
72 }
73
74 #[inline]
75 fn end(&self) -> Option<Idx> {
76 self.end.clone()
77 }
78}
79
80pub trait Range<Idx: Clone + Ord = usize> {
81 fn start(&self) -> Idx;
82 fn end(&self) -> Idx;
83
84 #[inline]
85 #[must_use]
86 fn clamp(&self, start: impl Into<Idx>, end: impl Into<Idx>) -> ops::Range<Idx> {
87 let end = self.end().min(end.into());
88 let start = self.start().max(start.into()).min(end.clone());
89
90 start..end
91 }
92
93 #[inline]
94 #[must_use]
95 fn clamp_left(&self, start: impl Into<Idx>) -> ops::Range<Idx> {
96 self.clamp(start, self.end())
97 }
98
99 #[inline]
100 #[must_use]
101 fn clamp_right(&self, end: impl Into<Idx>) -> ops::Range<Idx> {
102 self.clamp(self.start(), end)
103 }
104
105 #[inline]
106 #[must_use]
107 fn intersection<T, R>(&self, other: R) -> ops::Range<Idx>
108 where
109 T: Clone + Ord + Into<Idx>,
110 R: Range<T>,
111 {
112 self.clamp(other.start(), other.end())
113 }
114
115 #[inline]
116 #[must_use]
117 fn to_open_range(&self) -> OpenRange<Idx> {
118 OpenRange {
119 start: self.start(),
120 end: Some(self.end()),
121 }
122 }
123}
124
125impl<Idx: Clone + Ord> Range<Idx> for ops::Range<Idx> {
126 fn start(&self) -> Idx {
127 self.start.clone()
128 }
129
130 fn end(&self) -> Idx {
131 self.end.clone()
132 }
133}
134
135impl<Idx: Clone + Ord> PartialRange<Idx> for ops::Range<Idx> {
136 fn start(&self) -> Idx {
137 self.start.clone()
138 }
139
140 fn end(&self) -> Option<Idx> {
141 Some(self.end.clone())
142 }
143}
144
145impl<Idx: Clone + Ord> PartialRange<Idx> for ops::RangeFrom<Idx> {
146 fn start(&self) -> Idx {
147 self.start.clone()
148 }
149
150 fn end(&self) -> Option<Idx> {
151 None
152 }
153}
154
155impl<Idx: Clone + Ord + Zero> PartialRange<Idx> for ops::RangeFull {
156 fn start(&self) -> Idx {
157 Zero::zero()
158 }
159
160 fn end(&self) -> Option<Idx> {
161 None
162 }
163}
164
165impl<Idx: Copy + One + Ord + SaturatingAdd> Range<Idx> for ops::RangeInclusive<Idx> {
166 fn start(&self) -> Idx {
167 *self.start()
168 }
169
170 fn end(&self) -> Idx {
171 self.end().saturating_add(&One::one())
172 }
173}
174
175impl<Idx: Copy + One + Ord + SaturatingAdd> PartialRange<Idx> for ops::RangeInclusive<Idx> {
176 fn start(&self) -> Idx {
177 *self.start()
178 }
179
180 fn end(&self) -> Option<Idx> {
181 Some(self.end().saturating_add(&One::one()))
182 }
183}
184
185impl<Idx: Copy + Ord + Zero> Range<Idx> for ops::RangeTo<Idx> {
186 fn start(&self) -> Idx {
187 Zero::zero()
188 }
189
190 fn end(&self) -> Idx {
191 self.end
192 }
193}
194
195impl<Idx: Copy + Ord + Zero> PartialRange<Idx> for ops::RangeTo<Idx> {
196 fn start(&self) -> Idx {
197 Zero::zero()
198 }
199
200 fn end(&self) -> Option<Idx> {
201 Some(self.end)
202 }
203}
204
205impl<Idx: Clone + One + Ord + SaturatingAdd + Zero> Range<Idx> for RangeToInclusive<Idx> {
206 fn start(&self) -> Idx {
207 Zero::zero()
208 }
209
210 fn end(&self) -> Idx {
211 self.end.saturating_add(&One::one())
212 }
213}
214
215impl<Idx: Clone + One + Ord + SaturatingAdd + Zero> PartialRange<Idx> for RangeToInclusive<Idx> {
216 fn start(&self) -> Idx {
217 Zero::zero()
218 }
219
220 fn end(&self) -> Option<Idx> {
221 Some(self.end.saturating_add(&One::one()))
222 }
223}
224
225impl<Idx: Clone + Ord, T: PartialRange<Idx>> PartialRange<Idx> for &T {
226 fn start(&self) -> Idx {
227 (*self).start()
228 }
229
230 fn end(&self) -> Option<Idx> {
231 (*self).end()
232 }
233}
234
235impl<Idx: Clone + Ord, T: Range<Idx>> Range<Idx> for &T {
236 fn start(&self) -> Idx {
237 (*self).start()
238 }
239
240 fn end(&self) -> Idx {
241 (*self).end()
242 }
243}