1use rand::distributions::uniform::{SampleRange, SampleUniform, UniformSampler};
4use rand::distributions::{Distribution, Standard};
5use rand::{Rng, RngCore};
6use serde::{Deserialize, Serialize};
7use std::ops::RangeBounds;
8
9#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone, Copy)]
11pub struct ValueBound<T> {
12 #[serde(skip_serializing_if = "Option::is_none")]
13 start: Option<T>,
14 #[serde(
15 skip_serializing_if = "skip_serialize_include_end",
16 default = "default_include_end"
17 )]
18 include_end: bool,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 end: Option<T>,
21}
22
23fn skip_serialize_include_end(b: &bool) -> bool {
24 b == &default_include_end()
25}
26
27fn default_include_end() -> bool {
28 true
29}
30
31impl<T> Default for ValueBound<T> {
32 fn default() -> Self {
33 ValueBound::<T>::new_full()
34 }
35}
36
37impl<T> ValueBound<T> {
38 pub fn new_full() -> Self {
42 Self::new(None, None)
43 }
44
45 pub fn new(start: Option<T>, end: Option<(bool, T)>) -> Self {
48 let (_include_end, _end): (bool, Option<T>) = match end {
49 None => (false, None),
50 Some((_include_end, _end)) => (_include_end, Some(_end)),
51 };
52
53 Self {
54 start,
55 end: _end,
56 include_end: _include_end,
57 }
58 }
59
60 pub fn get_start(&self) -> &Option<T> {
62 &self.start
63 }
64
65 pub fn get_end(&self) -> &Option<T> {
67 &self.end
68 }
69
70 pub fn is_include_end(&self) -> bool {
72 self.include_end
73 }
74
75 pub fn convert_into<U>(self) -> ValueBound<U>
77 where
78 T: Into<U>,
79 {
80 self.convert_with(|v| v.into())
81 }
82
83 pub fn convert_with<F, U>(self, mut convert: F) -> ValueBound<U>
85 where
86 F: FnMut(T) -> U,
87 {
88 let Self {
89 start,
90 include_end,
91 end,
92 } = self;
93
94 ValueBound {
95 start: start.map(|s| {
96 #[allow(clippy::redundant_closure)]
97 convert(s)
98 }),
99 include_end,
100 end: end.map(|e| {
101 #[allow(clippy::redundant_closure)]
102 convert(e)
103 }),
104 }
105 }
106
107 pub fn try_convert_with<F, U, E>(self, mut convert: F) -> Result<ValueBound<U>, E>
109 where
110 F: FnMut(T) -> Result<U, E>,
111 {
112 let Self {
113 start,
114 include_end,
115 end,
116 } = self;
117
118 let _start = match start {
119 None => None,
120 Some(s) => Some(convert(s)?),
121 };
122
123 let _end = match end {
124 None => None,
125 Some(e) => Some(convert(e)?),
126 };
127
128 Ok(ValueBound {
129 start: _start,
130 include_end,
131 end: _end,
132 })
133 }
134
135 pub fn without_no_bound_from_other(self, other: ValueBound<T>) -> ValueBound<T> {
137 let Self {
138 start,
139 include_end,
140 end,
141 } = self;
142 let Self {
143 start: other_start,
144 include_end: other_include_end,
145 end: other_end,
146 } = other;
147
148 ValueBound {
149 start: start.or(other_start),
150 include_end: if end.is_some() {
151 include_end
152 } else {
153 other_include_end
154 },
155 end: end.or(other_end),
156 }
157 }
158}
159
160impl<T: std::cmp::PartialOrd> ValueBound<T> {
161 pub fn contains(&self, v: &T) -> bool {
163 let Self {
164 start,
165 include_end,
166 end,
167 } = &self;
168
169 match (start, include_end, end) {
170 (None, _, None) => (..).contains(&v),
171 (None, true, Some(e)) => (..=e).contains(&v),
172 (None, false, Some(e)) => (..e).contains(&v),
173 (Some(s), _, None) => (s..).contains(&v),
174 (Some(s), true, Some(e)) => (s..=e).contains(&v),
175 (Some(s), false, Some(e)) => (s..e).contains(&v),
176 }
177 }
178
179 pub fn is_empty(&self) -> bool {
181 let Self {
182 start,
183 include_end,
184 end,
185 } = &self;
186 match (start, include_end, end) {
187 (None, _, None) => false,
188 (None, true, Some(_)) => false,
189 (None, false, Some(_)) => true,
191 (Some(_), _, None) => false,
193 (Some(s), true, Some(e)) => (s..=e).is_empty(),
194 (Some(s), false, Some(e)) => (s..e).is_empty(),
195 }
196 }
197}
198
199impl<T: std::fmt::Display> std::fmt::Display for ValueBound<T> {
200 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201 let Self {
202 start,
203 include_end,
204 end,
205 } = &self;
206
207 match (start, end, include_end) {
208 (Some(s), Some(e), true) => write!(f, "{}..={}", s, e),
209 (Some(s), Some(e), false) => write!(f, "{}..{}", s, e),
210 (Some(s), None, _) => write!(f, "{}..", s),
211 (None, Some(e), true) => write!(f, "..={}", e),
212 (None, Some(e), false) => write!(f, "..{}", e),
213 (None, None, _) => write!(f, "..",),
214 }
215 }
216}
217
218impl<T: PartialOrd> From<std::ops::RangeFull> for ValueBound<T> {
219 fn from(_range: std::ops::RangeFull) -> Self {
220 ValueBound::new(None, None)
221 }
222}
223
224impl<T: PartialOrd> From<std::ops::Range<T>> for ValueBound<T> {
225 fn from(range: std::ops::Range<T>) -> Self {
226 let std::ops::Range { start, end } = range;
227 ValueBound::new(Some(start), Some((false, end)))
228 }
229}
230
231impl<T: PartialOrd> From<std::ops::RangeFrom<T>> for ValueBound<T> {
232 fn from(range: std::ops::RangeFrom<T>) -> Self {
233 let std::ops::RangeFrom { start } = range;
234 ValueBound::new(Some(start), None)
235 }
236}
237
238impl<T: PartialOrd> From<std::ops::RangeInclusive<T>> for ValueBound<T> {
239 fn from(range: std::ops::RangeInclusive<T>) -> Self {
240 let (start, end) = range.into_inner();
241 ValueBound::new(Some(start), Some((true, end)))
242 }
243}
244
245impl<T: PartialOrd> From<std::ops::RangeTo<T>> for ValueBound<T> {
246 fn from(range: std::ops::RangeTo<T>) -> Self {
247 let std::ops::RangeTo { end } = range;
248 ValueBound::new(None, Some((false, end)))
249 }
250}
251
252impl<T: PartialOrd> From<std::ops::RangeToInclusive<T>> for ValueBound<T> {
253 fn from(range: std::ops::RangeToInclusive<T>) -> Self {
254 let std::ops::RangeToInclusive { end } = range;
255 ValueBound::new(None, Some((true, end)))
256 }
257}
258
259impl<T: SampleUniform + PartialOrd> SampleRange<T> for ValueBound<T>
260where
261 Standard: Distribution<T>,
262{
263 #[inline]
264 fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> T {
265 if self.start.is_none() || self.end.is_none() {
266 loop {
267 let s = rng.gen::<T>();
268 if self.contains(&s) {
269 return s;
270 }
271 }
272 }
273
274 match (self.start, self.end) {
275 (Some(s), Some(e)) => {
276 if self.include_end {
277 T::Sampler::sample_single_inclusive(s, e, rng)
278 } else {
279 T::Sampler::sample_single(s, e, rng)
280 }
281 }
282 (_, _) => unreachable!(),
283 }
284 }
285
286 #[inline]
287 fn is_empty(&self) -> bool {
288 self.is_empty()
289 }
290}