1use crate::{
22 iterators::IntervalIterator,
23 numerated::{Bound, Numerated},
24};
25use core::{
26 fmt::{self, Debug, Formatter},
27 ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
28};
29use num_traits::{
30 CheckedAdd, One, Zero,
31 bounds::{LowerBounded, UpperBounded},
32};
33
34#[derive(Clone, Copy, PartialEq, Eq, derive_more::Display)]
36#[display("{start}..={end}")]
37pub struct Interval<T> {
38 start: T,
39 end: T,
40}
41
42impl<T: Numerated> Interval<T> {
43 #[track_caller]
50 pub unsafe fn new_unchecked(start: T, end: T) -> Self {
51 debug_assert!(
52 start <= end,
53 "Calling this method you must guarantee that `start ≤ end`"
54 );
55 Self { start, end }
56 }
57
58 pub fn new(start: T, end: T) -> Option<Self> {
60 (start <= end).then_some(Self { start, end })
61 }
62
63 pub fn start(&self) -> T {
65 self.start
66 }
67
68 pub fn end(&self) -> T {
70 self.end
71 }
72
73 pub fn iter(&self) -> IntervalIterator<T> {
75 (*self).into()
76 }
77
78 pub fn into_parts(self) -> (T, T) {
80 self.into()
81 }
82
83 pub fn inc_start(&self) -> Option<Self> {
85 let (start, end) = (self.start, self.end);
86 debug_assert!(start <= end, "It's guaranteed by `Interval`");
87 start.inc_if_lt(end).map(|start| {
88 debug_assert!(start <= end, "`T: Numerated` impl error");
89 Interval { start, end }
90 })
91 }
92
93 pub fn try_from_range(range: Range<T>) -> Result<Self, TryFromRangeError> {
97 let (start, end) = (range.start, range.end);
98 end.dec_if_gt(start)
99 .map(|end| {
100 debug_assert!(start <= end, "`T: Numerated` impl error");
101 Self { start, end }
102 })
103 .ok_or(if start == end {
104 TryFromRangeError::EmptyRange
105 } else {
106 TryFromRangeError::IncorrectRange
107 })
108 }
109}
110
111impl<T: Numerated> PartialEq<RangeInclusive<T>> for Interval<T> {
112 fn eq(&self, other: &RangeInclusive<T>) -> bool {
113 let (start, end) = self.into_parts();
114 (start, end) == (*other.start(), *other.end())
115 }
116}
117
118impl<T: Numerated> From<Interval<T>> for (T, T) {
119 fn from(interval: Interval<T>) -> (T, T) {
120 (interval.start, interval.end)
121 }
122}
123
124impl<T: Numerated> From<Interval<T>> for RangeInclusive<T> {
125 fn from(interval: Interval<T>) -> Self {
126 interval.start..=interval.end
127 }
128}
129
130impl<T: Numerated> From<T> for Interval<T> {
131 fn from(point: T) -> Self {
132 let (start, end) = (point, point);
133 debug_assert!(start <= end, "`T: Ord` impl error");
134 Self { start, end }
135 }
136}
137
138impl<T: Numerated + LowerBounded> From<RangeToInclusive<T>> for Interval<T> {
139 fn from(range: RangeToInclusive<T>) -> Self {
140 let (start, end) = (T::min_value(), range.end);
141 debug_assert!(start <= end, "`T: LowerBounded` impl error");
142 Self { start, end }
143 }
144}
145
146impl<T: Numerated + UpperBounded + LowerBounded> From<RangeFull> for Interval<T> {
147 fn from(_: RangeFull) -> Self {
148 let (start, end) = (T::min_value(), T::max_value());
149 debug_assert!(start <= end, "`T: UpperBounded + LowerBounded` impl error");
150 Self { start, end }
151 }
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub struct EmptyRangeError;
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
160pub struct IncorrectRangeError;
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub enum TryFromRangeError {
165 EmptyRange,
167 IncorrectRange,
169}
170
171impl<T: Numerated + UpperBounded, I: Into<T::Bound>> TryFrom<RangeFrom<I>> for Interval<T> {
172 type Error = EmptyRangeError;
173
174 fn try_from(range: RangeFrom<I>) -> Result<Self, Self::Error> {
175 match Into::<T::Bound>::into(range.start).unbound() {
176 Some(start) => {
177 let end = T::max_value();
178 debug_assert!(start <= end, "`T: UpperBounded` impl error");
179 Ok(Self { start, end })
180 }
181 None => Err(EmptyRangeError),
182 }
183 }
184}
185
186impl<T: Numerated + LowerBounded + UpperBounded, I: Into<T::Bound>> TryFrom<RangeTo<I>>
187 for Interval<T>
188{
189 type Error = EmptyRangeError;
190
191 fn try_from(range: RangeTo<I>) -> Result<Self, Self::Error> {
192 let end: T::Bound = range.end.into();
193
194 let Some(end) = end.unbound() else {
195 return Ok(Self::from(..));
196 };
197
198 let start = T::min_value();
199 end.dec_if_gt(start)
200 .map(|end| {
201 debug_assert!(start <= end, "`T: LowerBounded` impl error");
202 Self { start, end }
203 })
204 .ok_or(EmptyRangeError)
205 }
206}
207
208impl<T: Numerated> TryFrom<RangeInclusive<T>> for Interval<T> {
209 type Error = IncorrectRangeError;
210
211 fn try_from(range: RangeInclusive<T>) -> Result<Self, Self::Error> {
212 let (start, end) = range.into_inner();
213 (start <= end)
214 .then_some(Self { start, end })
215 .ok_or(IncorrectRangeError)
216 }
217}
218
219impl<T, S, E> TryFrom<(S, E)> for Interval<T>
220where
221 T: Numerated + UpperBounded,
222 S: Into<T::Bound>,
223 E: Into<T::Bound>,
224{
225 type Error = TryFromRangeError;
226
227 fn try_from((start, end): (S, E)) -> Result<Self, Self::Error> {
229 let start: T::Bound = start.into();
230 let end: T::Bound = end.into();
231
232 match (start.unbound(), end.unbound()) {
233 (None, None) => Err(TryFromRangeError::EmptyRange),
234 (None, Some(_)) => Err(TryFromRangeError::IncorrectRange),
235 (start, None) => Self::try_from(start..).map_err(|_| TryFromRangeError::EmptyRange),
236 (Some(start), Some(end)) => Self::try_from_range(start..end),
237 }
238 }
239}
240
241impl<T: Numerated + UpperBounded, I: Into<T::Bound>> TryFrom<Range<I>> for Interval<T> {
242 type Error = TryFromRangeError;
243
244 fn try_from(range: Range<I>) -> Result<Self, Self::Error> {
245 Self::try_from((range.start, range.end))
246 }
247}
248
249#[derive(Debug, Clone, Copy, PartialEq, Eq)]
251pub enum NewWithLenError {
252 ZeroLen,
254 OutOfBounds,
256}
257
258impl<T: Numerated + UpperBounded> Interval<T> {
259 pub fn with_len<S: Into<T::Bound>, L: Into<Option<T::Distance>>>(
264 start: S,
265 len: L,
266 ) -> Result<Interval<T>, NewWithLenError> {
267 let start: T::Bound = start.into();
268 let len: Option<T::Distance> = len.into();
269 match (start.unbound(), len) {
270 (_, Some(len)) if len.is_zero() => Err(NewWithLenError::ZeroLen),
271 (None, _) => Err(NewWithLenError::OutOfBounds),
272 (Some(start), len) => {
273 let distance = len
275 .map(|len| len - T::Distance::one())
276 .unwrap_or(T::Distance::max_value());
277 start
278 .add_if_enclosed_by(distance, T::max_value())
279 .map(|end| {
280 debug_assert!(start <= end, "`T: Numerated` impl error");
281 Self { start, end }
282 })
283 .ok_or(NewWithLenError::OutOfBounds)
284 }
285 }
286 }
287}
288
289impl<T: Numerated> Interval<T> {
290 pub fn raw_len(&self) -> Option<T::Distance> {
293 let (start, end) = self.into_parts();
294 end.distance(start).checked_add(&T::Distance::one())
295 }
296}
297
298impl<T: Numerated + LowerBounded + UpperBounded> Interval<T> {
299 pub fn len(&self) -> T::Bound {
306 self.raw_len()
307 .and_then(|raw_len| T::min_value().add_if_enclosed_by(raw_len, T::max_value()))
308 .into()
309 }
310}
311
312impl<T: Debug> Debug for Interval<T> {
313 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
314 write!(f, "{:?}..={:?}", self.start, self.end)
315 }
316}
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321
322 #[test]
323 fn len() {
324 assert_eq!(Interval::<u8>::try_from(1..7).unwrap().len(), 6);
325 assert_eq!(Interval::<u8>::try_from(..1).unwrap().len(), 1);
326 assert_eq!(Interval::<u8>::from(..=1).len(), 2);
327 assert_eq!(Interval::<u8>::try_from(1..).unwrap().len(), 255);
328 assert_eq!(Interval::<u8>::try_from(0..).unwrap().len(), None);
329 assert_eq!(Interval::<u8>::from(..).len(), None);
330
331 assert_eq!(Interval::<u8>::try_from(1..7).unwrap().raw_len(), Some(6));
332 assert_eq!(Interval::<u8>::try_from(..1).unwrap().raw_len(), Some(1));
333 assert_eq!(Interval::<u8>::from(..=1).raw_len(), Some(2));
334 assert_eq!(Interval::<u8>::try_from(1..).unwrap().raw_len(), Some(255));
335 assert_eq!(Interval::<u8>::try_from(0..).unwrap().raw_len(), None);
336 assert_eq!(Interval::<u8>::from(..).raw_len(), None);
337
338 assert_eq!(Interval::<i8>::try_from(-1..1).unwrap().len(), -126); assert_eq!(Interval::<i8>::from(..=1).len(), 2); assert_eq!(Interval::<i8>::try_from(..1).unwrap().len(), 1); assert_eq!(Interval::<i8>::try_from(1..).unwrap().len(), -1); assert_eq!(Interval::<i8>::from(..).len(), None); assert_eq!(Interval::<i8>::try_from(-1..1).unwrap().raw_len(), Some(2));
345 assert_eq!(Interval::<i8>::try_from(..1).unwrap().raw_len(), Some(129));
346 assert_eq!(Interval::<i8>::from(..=1).raw_len(), Some(130));
347 assert_eq!(Interval::<i8>::try_from(1..).unwrap().raw_len(), Some(127));
348 assert_eq!(Interval::<i8>::from(..).raw_len(), None);
349 }
350
351 #[test]
352 fn count_from() {
353 assert_eq!(Interval::<u8>::with_len(0, 100).unwrap(), 0..=99);
354 assert_eq!(Interval::<u8>::with_len(0, 255).unwrap(), 0..=254);
355 assert_eq!(Interval::<u8>::with_len(0, None).unwrap(), 0..=255);
356 assert_eq!(Interval::<u8>::with_len(1, 255).unwrap(), 1..=255);
357 assert_eq!(Interval::<u8>::with_len(0, 1).unwrap(), 0..=0);
358 }
359}