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