commonware_codec/
config.rs1use core::ops::{Bound, RangeBounds};
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
32pub struct RangeCfg<T: Copy + PartialOrd> {
33 start: Bound<T>,
35
36 end: Bound<T>,
38}
39
40impl<T: Copy + PartialOrd> From<core::ops::Range<T>> for RangeCfg<T> {
41 fn from(r: core::ops::Range<T>) -> Self {
42 Self::new(r)
43 }
44}
45
46impl<T: Copy + PartialOrd> From<core::ops::RangeInclusive<T>> for RangeCfg<T> {
47 fn from(r: core::ops::RangeInclusive<T>) -> Self {
48 Self::new(r)
49 }
50}
51
52impl<T: Copy + PartialOrd> From<core::ops::RangeFrom<T>> for RangeCfg<T> {
53 fn from(r: core::ops::RangeFrom<T>) -> Self {
54 Self::new(r)
55 }
56}
57
58impl<T: Copy + PartialOrd> From<core::ops::RangeTo<T>> for RangeCfg<T> {
59 fn from(r: core::ops::RangeTo<T>) -> Self {
60 Self::new(r)
61 }
62}
63
64impl<T: Copy + PartialOrd> From<core::ops::RangeToInclusive<T>> for RangeCfg<T> {
65 fn from(r: core::ops::RangeToInclusive<T>) -> Self {
66 Self::new(r)
67 }
68}
69
70impl<T: Copy + PartialOrd> From<core::ops::RangeFull> for RangeCfg<T> {
71 fn from(_: core::ops::RangeFull) -> Self {
72 Self::new(..)
73 }
74}
75
76impl<T: Copy + PartialOrd> RangeCfg<T> {
77 pub fn new(r: impl RangeBounds<T>) -> Self {
88 RangeCfg {
89 start: r.start_bound().cloned(),
90 end: r.end_bound().cloned(),
91 }
92 }
93
94 pub fn exact(value: T) -> Self {
96 Self {
97 start: Bound::Included(value),
98 end: Bound::Included(value),
99 }
100 }
101
102 pub fn contains(&self, value: &T) -> bool {
104 match &self.start {
106 Bound::Included(s) if value < s => return false,
107 Bound::Excluded(s) if value <= s => return false,
108 _ => {}
109 }
110
111 match &self.end {
113 Bound::Included(e) if value > e => return false,
114 Bound::Excluded(e) if value >= e => return false,
115 _ => {}
116 }
117
118 true
120 }
121}
122
123impl<T: Copy + PartialOrd> RangeBounds<T> for RangeCfg<T> {
124 fn start_bound(&self) -> Bound<&T> {
125 self.start.as_ref()
126 }
127
128 fn end_bound(&self) -> Bound<&T> {
129 self.end.as_ref()
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use core::ops::Bound::{Excluded, Included, Unbounded};
137
138 #[test]
139 fn test_range_cfg_from() {
140 let cfg_full: RangeCfg<usize> = (..).into();
142 assert_eq!(
143 cfg_full,
144 RangeCfg {
145 start: Unbounded,
146 end: Unbounded
147 }
148 );
149
150 let cfg_start_incl: RangeCfg<usize> = (5..).into();
152 assert_eq!(
153 cfg_start_incl,
154 RangeCfg {
155 start: Included(5),
156 end: Unbounded
157 }
158 );
159
160 let cfg_end_excl: RangeCfg<usize> = (..10).into();
162 assert_eq!(
163 cfg_end_excl,
164 RangeCfg {
165 start: Unbounded,
166 end: Excluded(10)
167 }
168 );
169
170 let cfg_end_incl: RangeCfg<usize> = (..=10).into();
172 assert_eq!(
173 cfg_end_incl,
174 RangeCfg {
175 start: Unbounded,
176 end: Included(10)
177 }
178 );
179
180 let cfg_incl_excl: RangeCfg<usize> = (5..10).into();
182 assert_eq!(
183 cfg_incl_excl,
184 RangeCfg {
185 start: Included(5),
186 end: Excluded(10)
187 }
188 );
189
190 let cfg_incl_incl: RangeCfg<usize> = (5..=10).into();
192 assert_eq!(
193 cfg_incl_incl,
194 RangeCfg {
195 start: Included(5),
196 end: Included(10)
197 }
198 );
199
200 struct ExclusiveStartRange(usize, usize);
202 impl RangeBounds<usize> for ExclusiveStartRange {
203 fn start_bound(&self) -> Bound<&usize> {
204 Excluded(&self.0)
205 }
206 fn end_bound(&self) -> Bound<&usize> {
207 Included(&self.1)
208 }
209 }
210 let cfg_excl_incl = RangeCfg::new(ExclusiveStartRange(5, 10));
211 assert_eq!(
212 cfg_excl_incl,
213 RangeCfg {
214 start: Excluded(5),
215 end: Included(10)
216 }
217 );
218 }
219
220 #[test]
221 fn test_range_cfg_contains() {
222 let cfg_unbounded: RangeCfg<usize> = (..).into();
224 assert!(cfg_unbounded.contains(&0));
225 assert!(cfg_unbounded.contains(&100));
226 assert!(cfg_unbounded.contains(&usize::MAX));
227
228 let cfg_start_incl: RangeCfg<usize> = (5..).into();
230 assert!(!cfg_start_incl.contains(&4));
231 assert!(cfg_start_incl.contains(&5));
232 assert!(cfg_start_incl.contains(&6));
233 assert!(cfg_start_incl.contains(&usize::MAX));
234
235 let cfg_end_excl: RangeCfg<usize> = (..10).into();
237 assert!(cfg_end_excl.contains(&0));
238 assert!(cfg_end_excl.contains(&9));
239 assert!(!cfg_end_excl.contains(&10));
240 assert!(!cfg_end_excl.contains(&11));
241
242 let cfg_end_incl: RangeCfg<usize> = (..=10).into();
244 assert!(cfg_end_incl.contains(&0));
245 assert!(cfg_end_incl.contains(&9));
246 assert!(cfg_end_incl.contains(&10));
247 assert!(!cfg_end_incl.contains(&11));
248
249 let cfg_incl_excl: RangeCfg<usize> = (5..10).into();
251 assert!(!cfg_incl_excl.contains(&4));
252 assert!(cfg_incl_excl.contains(&5));
253 assert!(cfg_incl_excl.contains(&9));
254 assert!(!cfg_incl_excl.contains(&10));
255 assert!(!cfg_incl_excl.contains(&11));
256
257 let cfg_incl_incl: RangeCfg<usize> = (5..=10).into();
259 assert!(!cfg_incl_incl.contains(&4));
260 assert!(cfg_incl_incl.contains(&5));
261 assert!(cfg_incl_incl.contains(&9));
262 assert!(cfg_incl_incl.contains(&10));
263 assert!(!cfg_incl_incl.contains(&11));
264
265 let cfg_excl_incl = RangeCfg {
267 start: Excluded(5),
268 end: Included(10),
269 };
270 assert!(!cfg_excl_incl.contains(&4));
271 assert!(!cfg_excl_incl.contains(&5)); assert!(cfg_excl_incl.contains(&6));
273 assert!(cfg_excl_incl.contains(&10)); assert!(!cfg_excl_incl.contains(&11));
275
276 let cfg_excl_excl = RangeCfg {
278 start: Excluded(5),
279 end: Excluded(10),
280 };
281 assert!(!cfg_excl_excl.contains(&5)); assert!(cfg_excl_excl.contains(&6));
283 assert!(cfg_excl_excl.contains(&9));
284 assert!(!cfg_excl_excl.contains(&10)); }
286
287 #[test]
288 fn test_contains_empty_range() {
289 let cfg_empty_excl: RangeCfg<usize> = (5..5).into();
291 assert!(!cfg_empty_excl.contains(&4));
292 assert!(!cfg_empty_excl.contains(&5));
293 assert!(!cfg_empty_excl.contains(&6));
294
295 #[allow(clippy::reversed_empty_ranges)]
297 let cfg_empty_incl: RangeCfg<usize> = (6..=5).into();
298 assert!(!cfg_empty_incl.contains(&5));
299 assert!(!cfg_empty_incl.contains(&6));
300 }
301
302 #[test]
303 fn test_range_cfg_u8() {
304 let cfg = RangeCfg::new(0u8..=255u8);
306 assert!(cfg.contains(&0));
307 assert!(cfg.contains(&128));
308 assert!(cfg.contains(&255));
309
310 let cfg_partial = RangeCfg::new(10u8..20u8);
311 assert!(!cfg_partial.contains(&9));
312 assert!(cfg_partial.contains(&10));
313 assert!(cfg_partial.contains(&19));
314 assert!(!cfg_partial.contains(&20));
315 }
316
317 #[test]
318 fn test_range_cfg_u16() {
319 let cfg = RangeCfg::new(100u16..=1000u16);
321 assert!(!cfg.contains(&99));
322 assert!(cfg.contains(&100));
323 assert!(cfg.contains(&500));
324 assert!(cfg.contains(&1000));
325 assert!(!cfg.contains(&1001));
326 }
327
328 #[test]
329 fn test_range_cfg_u32() {
330 let cfg = RangeCfg::new(0u32..1024u32);
332 assert!(cfg.contains(&0));
333 assert!(cfg.contains(&512));
334 assert!(!cfg.contains(&1024));
335 assert!(!cfg.contains(&2000));
336 }
337
338 #[test]
339 fn test_range_cfg_u64() {
340 let cfg = RangeCfg::new(1000u64..);
342 assert!(!cfg.contains(&999));
343 assert!(cfg.contains(&1000));
344 assert!(cfg.contains(&u64::MAX));
345 }
346
347 #[test]
348 fn test_type_inference() {
349 let cfg = RangeCfg::new(0u8..10u8);
351 assert!(cfg.contains(&5u8));
352
353 let cfg: RangeCfg<u32> = RangeCfg::new(0..1000);
355 assert!(cfg.contains(&500));
356 }
357}