spru_util/counter/
range_type.rs1use std::ops::{self, RangeBounds as _};
2
3use super::CounterType;
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash)]
6pub enum RangeType<T> {
7 Full(ops::RangeFull),
8 From(ops::RangeFrom<T>),
9 Inclusive(ops::RangeInclusive<T>),
10 ToInclusive(ops::RangeToInclusive<T>),
11 Exclusive(ops::Range<T>),
12 ToExclusive(ops::RangeTo<T>),
13}
14
15impl<T: CounterType> RangeType<T> {
16 pub fn constrain(&self, value: T) -> T {
17 let start = match self.start_bound() {
18 ops::Bound::Included(start) => Some(start.clone()),
19 ops::Bound::Excluded(_) | ops::Bound::Unbounded => None,
20 };
21 let end = match self.end_bound() {
22 ops::Bound::Included(end) => Some(end.clone()),
23 ops::Bound::Excluded(end) => Some(end.clone() - num_traits::One::one()),
24 ops::Bound::Unbounded => None,
25 };
26 match (start, end) {
27 (None, None) => value,
28 (None, Some(end)) => num_traits::clamp_max(value, end),
29 (Some(start), None) => num_traits::clamp_min(value, start),
30 (Some(start), Some(end)) => num_traits::clamp(value, start, end),
31 }
32 }
33}
34
35impl<T: serde::Serialize> serde::Serialize for RangeType<T> {
36 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
37 where
38 S: serde::Serializer,
39 {
40 let start = self.start_bound();
41 let end = self.end_bound();
42 (start, end).serialize(serializer)
43 }
44}
45
46impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for RangeType<T> {
47 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
48 where
49 D: serde::Deserializer<'de>,
50 {
51 let (start, end) = <(ops::Bound<T>, ops::Bound<T>)>::deserialize(deserializer)?;
52 let value = match (start, end) {
53 (ops::Bound::Included(start), ops::Bound::Included(end)) => {
57 Self::Inclusive(start..=end)
58 }
59 (ops::Bound::Included(start), ops::Bound::Excluded(end)) => Self::Exclusive(start..end),
60 (ops::Bound::Included(start), ops::Bound::Unbounded) => Self::From(start..),
61 (ops::Bound::Unbounded, ops::Bound::Included(end)) => Self::ToInclusive(..=end),
62 (ops::Bound::Unbounded, ops::Bound::Excluded(end)) => Self::ToExclusive(..end),
63 (ops::Bound::Unbounded, ops::Bound::Unbounded) => Self::Full(ops::RangeFull),
64 (ops::Bound::Excluded(_), _) => {
65 return Err(<D::Error as serde::de::Error>::invalid_value(
66 serde::de::Unexpected::Other("excluded start bound"),
67 &"included or unbounded start",
68 ));
69 }
70 };
71 Ok(value)
72 }
73}
74
75impl<T> Default for RangeType<T> {
76 fn default() -> Self {
77 Self::Full(ops::RangeFull)
78 }
79}
80
81impl<T> ops::RangeBounds<T> for RangeType<T> {
82 fn start_bound(&self) -> ops::Bound<&T> {
83 match self {
84 RangeType::Full(r) => r.start_bound(),
85 RangeType::From(r) => r.start_bound(),
86 RangeType::Inclusive(r) => r.start_bound(),
87 RangeType::ToInclusive(r) => r.start_bound(),
88 RangeType::Exclusive(r) => r.start_bound(),
89 RangeType::ToExclusive(r) => r.start_bound(),
90 }
91 }
92
93 fn end_bound(&self) -> ops::Bound<&T> {
94 match self {
95 RangeType::Full(r) => r.end_bound(),
96 RangeType::From(r) => r.end_bound(),
97 RangeType::Inclusive(r) => r.end_bound(),
98 RangeType::ToInclusive(r) => r.end_bound(),
99 RangeType::Exclusive(r) => r.end_bound(),
100 RangeType::ToExclusive(r) => r.end_bound(),
101 }
102 }
103}
104
105impl<T> From<ops::RangeFull> for RangeType<T> {
106 fn from(value: ops::RangeFull) -> Self {
107 Self::Full(value)
108 }
109}
110
111impl<T> From<ops::RangeFrom<T>> for RangeType<T> {
112 fn from(value: ops::RangeFrom<T>) -> Self {
113 Self::From(value)
114 }
115}
116
117impl<T> From<ops::RangeInclusive<T>> for RangeType<T> {
118 fn from(value: ops::RangeInclusive<T>) -> Self {
119 Self::Inclusive(value)
120 }
121}
122
123impl<T> From<ops::RangeToInclusive<T>> for RangeType<T> {
124 fn from(value: ops::RangeToInclusive<T>) -> Self {
125 Self::ToInclusive(value)
126 }
127}
128
129impl<T> From<ops::Range<T>> for RangeType<T> {
130 fn from(value: ops::Range<T>) -> Self {
131 Self::Exclusive(value)
132 }
133}
134
135impl<T> From<ops::RangeTo<T>> for RangeType<T> {
136 fn from(value: ops::RangeTo<T>) -> Self {
137 Self::ToExclusive(value)
138 }
139}