1use ehttpd::err;
4use ehttpd::error::Error;
5use std::cmp::Ordering;
6use std::ops::{Bound, RangeBounds, RangeInclusive};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum AnyInclusiveRange<T> {
11 Full,
13 From {
15 start: T,
17 },
18 To {
20 end: T,
22 },
23 FromTo {
25 start: T,
27 end: T,
29 },
30}
31impl<T> AnyInclusiveRange<T> {
32 pub fn to_inclusive(&self, start_incl: T, end_incl: T) -> Result<RangeInclusive<T>, Error>
34 where
35 T: PartialOrd + Copy,
36 {
37 let start_incl = match self {
39 Self::Full | Self::To { .. } => start_incl,
40 Self::From { start } => *start,
41 Self::FromTo { start, .. } => *start,
42 };
43 let end_incl = match self {
44 Self::Full | Self::From { .. } => end_incl,
45 Self::To { end } => *end,
46 Self::FromTo { end, .. } => *end,
47 };
48
49 match start_incl.partial_cmp(&end_incl) {
51 Some(Ordering::Less | Ordering::Equal) => Ok(start_incl..=end_incl),
52 _ => Err(err!("End of inclusive range is before start")),
53 }
54 }
55
56 pub fn convert<U, E>(self) -> Result<AnyInclusiveRange<U>, E>
58 where
59 T: TryInto<U>,
60 E: From<<T as TryInto<U>>::Error>,
61 {
62 let range = match self {
63 Self::Full => AnyInclusiveRange::Full,
64 Self::From { start } => AnyInclusiveRange::From { start: start.try_into()? },
65 Self::To { end } => AnyInclusiveRange::To { end: end.try_into()? },
66 Self::FromTo { start, end } => AnyInclusiveRange::FromTo { start: start.try_into()?, end: end.try_into()? },
67 };
68 Ok(range)
69 }
70}
71impl<T> RangeBounds<T> for AnyInclusiveRange<T> {
72 fn start_bound(&self) -> Bound<&T> {
73 match self {
74 Self::Full | Self::To { .. } => Bound::Unbounded,
75 Self::From { start } | Self::FromTo { start, .. } => Bound::Included(start),
76 }
77 }
78 fn end_bound(&self) -> Bound<&T> {
79 match self {
80 AnyInclusiveRange::Full | AnyInclusiveRange::From { .. } => Bound::Unbounded,
81 AnyInclusiveRange::To { end } | AnyInclusiveRange::FromTo { end, .. } => Bound::Included(end),
82 }
83 }
84}