1use crate::{boolean::*, ErrorMessage, Predicate};
18#[cfg(feature = "alloc")]
19use alloc::{
20 collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque},
21 format,
22 string::String,
23 vec::Vec,
24};
25#[cfg(feature = "std")]
26use std::collections::{HashMap, HashSet};
27
28pub trait UnsignedBoundable {
30 fn bounding_value(&self) -> usize;
31}
32
33impl UnsignedBoundable for u8 {
34 fn bounding_value(&self) -> usize {
35 *self as usize
36 }
37}
38
39impl UnsignedBoundable for core::num::Saturating<u8> {
40 fn bounding_value(&self) -> usize {
41 self.0 as usize
42 }
43}
44
45impl UnsignedBoundable for core::num::NonZeroU8 {
46 fn bounding_value(&self) -> usize {
47 self.get() as usize
48 }
49}
50
51impl UnsignedBoundable for u16 {
52 fn bounding_value(&self) -> usize {
53 *self as usize
54 }
55}
56
57impl UnsignedBoundable for core::num::Saturating<u16> {
58 fn bounding_value(&self) -> usize {
59 self.0 as usize
60 }
61}
62
63impl UnsignedBoundable for core::num::NonZeroU16 {
64 fn bounding_value(&self) -> usize {
65 self.get() as usize
66 }
67}
68
69impl UnsignedBoundable for u32 {
70 fn bounding_value(&self) -> usize {
71 *self as usize
72 }
73}
74
75impl UnsignedBoundable for core::num::Saturating<u32> {
76 fn bounding_value(&self) -> usize {
77 self.0 as usize
78 }
79}
80
81impl UnsignedBoundable for core::num::NonZeroU32 {
82 fn bounding_value(&self) -> usize {
83 self.get() as usize
84 }
85}
86
87impl UnsignedBoundable for usize {
88 fn bounding_value(&self) -> usize {
89 *self
90 }
91}
92
93impl UnsignedBoundable for core::num::Saturating<usize> {
94 fn bounding_value(&self) -> usize {
95 self.0
96 }
97}
98
99impl UnsignedBoundable for core::num::NonZeroUsize {
100 fn bounding_value(&self) -> usize {
101 self.get()
102 }
103}
104
105#[cfg(target_pointer_width = "64")]
106impl UnsignedBoundable for u64 {
107 fn bounding_value(&self) -> usize {
108 *self as usize
109 }
110}
111
112#[cfg(target_pointer_width = "64")]
113impl UnsignedBoundable for core::num::Saturating<u64> {
114 fn bounding_value(&self) -> usize {
115 self.0 as usize
116 }
117}
118
119#[cfg(target_pointer_width = "64")]
120impl UnsignedBoundable for core::num::NonZeroU64 {
121 fn bounding_value(&self) -> usize {
122 self.get() as usize
123 }
124}
125
126#[macro_export]
144macro_rules! unsigned_boundable_via_len {
145 ($t:ident $(<$($ts:ident),+>)?) => {
146 impl $(<$($ts),+>)? UnsignedBoundable for $t $(<$($ts),+>)? {
147 fn bounding_value(&self) -> usize {
148 self.len()
149 }
150 }
151 };
152}
153
154#[cfg(feature = "alloc")]
155mod needs_alloc {
156 use super::*;
157
158 unsigned_boundable_via_len!(String);
159 unsigned_boundable_via_len!(BinaryHeap<T>);
160 unsigned_boundable_via_len!(BTreeMap<K, V>);
161 unsigned_boundable_via_len!(BTreeSet<T>);
162 unsigned_boundable_via_len!(LinkedList<T>);
163 unsigned_boundable_via_len!(Vec<T>);
164 unsigned_boundable_via_len!(VecDeque<T>);
165}
166
167#[cfg(feature = "std")]
168mod needs_std {
169 use super::*;
170
171 unsigned_boundable_via_len!(HashMap<K, V>);
172 unsigned_boundable_via_len!(HashSet<T>);
173}
174
175impl<T> UnsignedBoundable for [T] {
176 fn bounding_value(&self) -> usize {
177 self.len()
178 }
179}
180#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
181pub struct GreaterThan<const MIN: usize>;
182
183pub type GT<const MIN: usize> = GreaterThan<MIN>;
184
185impl<T: UnsignedBoundable, const MIN: usize> Predicate<T> for GreaterThan<MIN> {
186 fn test(value: &T) -> bool {
187 value.bounding_value() > MIN
188 }
189
190 #[cfg(feature = "alloc")]
191 fn error() -> ErrorMessage {
192 format!("must be greater than {}", MIN)
193 }
194
195 #[cfg(not(feature = "alloc"))]
196 fn error() -> ErrorMessage {
197 "greater than"
198 }
199
200 unsafe fn optimize(value: &T) {
201 core::hint::assert_unchecked(Self::test(value));
202 }
203}
204
205#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
206pub struct GreaterThanEqual<const MIN: usize>;
207
208pub type GTE<const MIN: usize> = GreaterThanEqual<MIN>;
209
210impl<T: UnsignedBoundable, const MIN: usize> Predicate<T> for GreaterThanEqual<MIN> {
211 fn test(value: &T) -> bool {
212 value.bounding_value() >= MIN
213 }
214
215 #[cfg(feature = "alloc")]
216 fn error() -> ErrorMessage {
217 format!("must be greater than or equal to {}", MIN)
218 }
219
220 #[cfg(not(feature = "alloc"))]
221 fn error() -> ErrorMessage {
222 "greater than equal"
223 }
224
225 unsafe fn optimize(value: &T) {
226 core::hint::assert_unchecked(Self::test(value));
227 }
228}
229
230#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
231pub struct LessThan<const MAX: usize>;
232
233pub type LT<const MAX: usize> = LessThan<MAX>;
234
235impl<T: UnsignedBoundable, const MAX: usize> Predicate<T> for LessThan<MAX> {
236 fn test(value: &T) -> bool {
237 value.bounding_value() < MAX
238 }
239
240 #[cfg(feature = "alloc")]
241 fn error() -> ErrorMessage {
242 format!("must be less than {}", MAX)
243 }
244
245 #[cfg(not(feature = "alloc"))]
246 fn error() -> ErrorMessage {
247 "less than"
248 }
249
250 unsafe fn optimize(value: &T) {
251 core::hint::assert_unchecked(Self::test(value));
252 }
253}
254
255#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
256pub struct LessThanEqual<const MAX: usize>;
257
258pub type LTE<const MAX: usize> = LessThanEqual<MAX>;
259
260impl<T: UnsignedBoundable, const MAX: usize> Predicate<T> for LessThanEqual<MAX> {
261 fn test(value: &T) -> bool {
262 value.bounding_value() <= MAX
263 }
264
265 #[cfg(feature = "alloc")]
266 fn error() -> ErrorMessage {
267 format!("must be less than or equal to {}", MAX)
268 }
269
270 #[cfg(not(feature = "alloc"))]
271 fn error() -> ErrorMessage {
272 "less than equal"
273 }
274
275 unsafe fn optimize(value: &T) {
276 core::hint::assert_unchecked(Self::test(value));
277 }
278}
279
280pub type OpenInterval<const MIN: usize, const MAX: usize> = And<GT<MIN>, LT<MAX>>;
281
282pub type OpenClosedInterval<const MIN: usize, const MAX: usize> = And<GT<MIN>, LTE<MAX>>;
283
284pub type ClosedOpenInterval<const MIN: usize, const MAX: usize> = And<GTE<MIN>, LT<MAX>>;
285
286pub type ClosedInterval<const MIN: usize, const MAX: usize> = And<GTE<MIN>, LTE<MAX>>;
287
288#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
289pub struct Modulo<const DIV: usize, const MOD: usize>;
290
291impl<T: UnsignedBoundable, const DIV: usize, const MOD: usize> Predicate<T> for Modulo<DIV, MOD> {
292 fn test(value: &T) -> bool {
293 value.bounding_value() % DIV == MOD
294 }
295
296 #[cfg(feature = "alloc")]
297 fn error() -> ErrorMessage {
298 format!("must be divisible by {} with a remainder of {}", DIV, MOD)
299 }
300
301 #[cfg(not(feature = "alloc"))]
302 fn error() -> ErrorMessage {
303 "modulo"
304 }
305
306 unsafe fn optimize(value: &T) {
307 core::hint::assert_unchecked(Self::test(value));
308 }
309}
310
311pub type Divisible<const DIV: usize> = Modulo<DIV, 0>;
312
313pub type Even = Modulo<2, 0>;
314
315pub type Odd = Not<Even>;
316
317#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
318pub struct Equals<const VAL: usize>;
319
320impl<T: UnsignedBoundable, const VAL: usize> Predicate<T> for Equals<VAL> {
321 fn test(value: &T) -> bool {
322 value.bounding_value() == VAL
323 }
324
325 #[cfg(feature = "alloc")]
326 fn error() -> ErrorMessage {
327 format!("must be equal to {}", VAL)
328 }
329
330 #[cfg(not(feature = "alloc"))]
331 fn error() -> ErrorMessage {
332 "equals"
333 }
334
335 unsafe fn optimize(value: &T) {
336 core::hint::assert_unchecked(Self::test(value));
337 }
338}
339
340pub type Zero = Equals<0>;
341
342pub type NonZero = Not<Zero>;
343
344#[cfg(test)]
345mod tests {
346 use super::*;
347 use crate::*;
348
349 #[test]
350 fn test_greater_than() {
351 type Test = Refinement<u64, GreaterThan<5>>;
352 assert!(Test::refine(6).is_ok());
353 assert!(Test::refine(5).is_err());
354 assert!(Test::refine(4).is_err());
355 }
356
357 #[test]
358 fn test_greater_than_equal() {
359 type Test = Refinement<u32, GreaterThanEqual<5>>;
360 assert!(Test::refine(6).is_ok());
361 assert!(Test::refine(5).is_ok());
362 assert!(Test::refine(4).is_err());
363 }
364
365 #[test]
366 fn test_less_than() {
367 type Test = Refinement<u16, LessThan<5>>;
368 assert!(Test::refine(4).is_ok());
369 assert!(Test::refine(5).is_err());
370 assert!(Test::refine(6).is_err());
371 }
372
373 #[test]
374 fn test_less_than_equal() {
375 type Test = Refinement<u8, LessThanEqual<5>>;
376 assert!(Test::refine(4).is_ok());
377 assert!(Test::refine(5).is_ok());
378 assert!(Test::refine(6).is_err());
379 }
380
381 #[test]
382 fn test_open_interval() {
383 type Test = Refinement<u8, OpenInterval<5, 10>>;
384 assert!(Test::refine(6).is_ok());
385 assert!(Test::refine(9).is_ok());
386 assert!(Test::refine(5).is_err());
387 assert!(Test::refine(10).is_err());
388 assert!(Test::refine(4).is_err());
389 assert!(Test::refine(11).is_err());
390 }
391
392 #[test]
393 fn test_open_closed_interval() {
394 type Test = Refinement<u16, OpenClosedInterval<5, 10>>;
395 assert!(Test::refine(6).is_ok());
396 assert!(Test::refine(9).is_ok());
397 assert!(Test::refine(5).is_err());
398 assert!(Test::refine(10).is_ok());
399 assert!(Test::refine(4).is_err());
400 assert!(Test::refine(11).is_err());
401 }
402
403 #[test]
404 fn test_closed_open_interval() {
405 type Test = Refinement<u32, ClosedOpenInterval<5, 10>>;
406 assert!(Test::refine(5).is_ok());
407 assert!(Test::refine(6).is_ok());
408 assert!(Test::refine(10).is_err());
409 assert!(Test::refine(4).is_err());
410 assert!(Test::refine(11).is_err());
411 }
412
413 #[test]
414 fn test_closed_interval() {
415 type Test = Refinement<u64, ClosedInterval<5, 10>>;
416 assert!(Test::refine(5).is_ok());
417 assert!(Test::refine(6).is_ok());
418 assert!(Test::refine(10).is_ok());
419 assert!(Test::refine(4).is_err());
420 assert!(Test::refine(11).is_err());
421 }
422
423 #[test]
424 fn test_equals() {
425 type Test = Refinement<u16, Equals<5>>;
426 assert!(Test::refine(5).is_ok());
427 assert!(Test::refine(6).is_err());
428 assert!(Test::refine(4).is_err());
429 }
430
431 #[test]
432 fn test_zero() {
433 type Test = Refinement<u8, Zero>;
434 assert!(Test::refine(0).is_ok());
435 assert!(Test::refine(1).is_err());
436 }
437
438 #[test]
439 fn test_non_zero() {
440 type Test = Refinement<u16, NonZero>;
441 assert!(Test::refine(1).is_ok());
442 assert!(Test::refine(0).is_err());
443 }
444
445 #[test]
446 fn test_modulo() {
447 type Test = Refinement<usize, Modulo<4, 2>>;
448 assert!(Test::refine(6).is_ok());
449 assert!(Test::refine(10).is_ok());
450 assert!(Test::refine(4).is_err());
451 }
452
453 #[test]
454 fn test_divisible() {
455 type Test = Refinement<usize, Divisible<4>>;
456 assert!(Test::refine(4).is_ok());
457 assert!(Test::refine(5).is_err());
458 }
459
460 #[test]
461 fn test_even() {
462 type Test = Refinement<usize, Even>;
463 assert!(Test::refine(4).is_ok());
464 assert!(Test::refine(0).is_ok());
465 assert!(Test::refine(5).is_err());
466 }
467
468 #[test]
469 fn test_odd() {
470 type Test = Refinement<usize, Odd>;
471 assert!(Test::refine(5).is_ok());
472 assert!(Test::refine(4).is_err());
473 assert!(Test::refine(0).is_err());
474 }
475}