refined/boundable/
unsigned.rs

1//! Boundable refinement via unsigned values.
2//!
3//! # Example
4//!
5//! ```
6//! use refined::{Refinement, RefinementOps, boundable::unsigned::GreaterThan};
7//!
8//! type SizedString = Refinement<String, GreaterThan<3>>;
9//!
10//! let ok_string = SizedString::refine("Good".to_string());
11//! assert!(ok_string.is_ok());
12//!
13//! let not_ok_string = SizedString::refine("Bad".to_string());
14//! assert!(not_ok_string.is_err());
15//! ```
16
17use 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
28/// Types that can be reduced to an unsigned size so that they can be bounded.
29pub 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/// Creates an [UnsignedBoundable] implementation for a struct that has a `len` method.
127///
128/// # Example
129///
130/// ```
131/// use refined::{unsigned_boundable_via_len, UnsignedBoundable};
132/// use std::collections::HashMap;
133///
134/// struct Wrapper<K, V> { inner: HashMap<K, V> };
135///
136/// impl<K, V> Wrapper<K, V> {
137///   pub fn len(&self) -> usize { self.inner.len() }
138/// }
139///
140/// unsigned_boundable_via_len!(Wrapper<K, V>);
141/// // `Wrapper<K, V> now implements `UnsignedBoundable`
142/// ```
143#[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}