competitive/num/
bounded.rs

1/// Trait for max/min bounds
2pub trait Bounded: Sized + PartialOrd {
3    fn maximum() -> Self;
4    fn minimum() -> Self;
5    fn is_maximum(&self) -> bool {
6        self == &Self::maximum()
7    }
8    fn is_minimum(&self) -> bool {
9        self == &Self::minimum()
10    }
11    fn set_maximum(&mut self) {
12        *self = Self::maximum()
13    }
14    fn set_minimum(&mut self) {
15        *self = Self::minimum()
16    }
17}
18
19macro_rules! impl_bounded_num {
20    ($($t:ident)*) => {
21        $(impl Bounded for $t {
22            fn maximum() -> Self { $t::MAX }
23            fn minimum() -> Self { $t::MIN }
24        })*
25    };
26}
27impl_bounded_num!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize f32 f64);
28
29macro_rules! impl_bounded_tuple {
30    (@impl $($T:ident)*) => {
31        impl<$($T: Bounded),*> Bounded for ($($T,)*) {
32            fn maximum() -> Self { ($(<$T as Bounded>::maximum(),)*) }
33            fn minimum() -> Self { ($(<$T as Bounded>::minimum(),)*) }
34        }
35    };
36    (@inner $($T:ident)*,) => {
37        impl_bounded_tuple!(@impl $($T)*);
38    };
39    (@inner $($T:ident)*, $U:ident $($Rest:ident)*) => {
40        impl_bounded_tuple!(@impl $($T)*);
41        impl_bounded_tuple!(@inner $($T)* $U, $($Rest)*);
42    };
43    ($T:ident $($Rest:ident)*) => {
44        impl_bounded_tuple!(@inner $T, $($Rest)*);
45    };
46}
47impl_bounded_tuple!(A B C D E F G H I J);
48
49impl Bounded for () {
50    fn maximum() -> Self {}
51    fn minimum() -> Self {}
52}
53impl Bounded for bool {
54    fn maximum() -> Self {
55        true
56    }
57    fn minimum() -> Self {
58        false
59    }
60}
61impl<T> Bounded for Option<T>
62where
63    T: Bounded,
64{
65    fn maximum() -> Self {
66        Some(<T as Bounded>::maximum())
67    }
68    fn minimum() -> Self {
69        None
70    }
71}
72impl<T> Bounded for std::cmp::Reverse<T>
73where
74    T: Bounded,
75{
76    fn maximum() -> Self {
77        std::cmp::Reverse(<T as Bounded>::minimum())
78    }
79    fn minimum() -> Self {
80        std::cmp::Reverse(<T as Bounded>::maximum())
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use std::cmp::Reverse;
88
89    fn assert_bounded<T: Bounded, I: Iterator<Item = T>>(iter: I) {
90        assert!(T::minimum() <= T::maximum());
91        for item in iter {
92            assert!(T::minimum() <= item);
93            assert!(item <= T::maximum());
94        }
95    }
96
97    #[test]
98    fn test_num_bounded() {
99        assert_bounded([0u32, 1, 2, !0].iter().cloned());
100        assert_bounded([0u64, 1, 2, !0].iter().cloned());
101        assert_bounded([0usize, 1, 2, !0].iter().cloned());
102        assert_bounded([0i32, 1, 2, !0].iter().cloned());
103        assert_bounded([0i64, 1, 2, !0].iter().cloned());
104        assert_bounded([0isize, 1, 2, !0].iter().cloned());
105        assert_bounded([false, true].iter().cloned());
106    }
107
108    #[test]
109    fn test_tuple_bounded() {
110        assert_bounded([(1, 0, 3)].iter().cloned());
111        assert_bounded([((), (1,), (2, 3))].iter().cloned());
112    }
113
114    #[test]
115    fn test_option_bounded() {
116        assert_bounded([None, Some((false, 3))].iter().cloned());
117    }
118
119    #[test]
120    fn test_reverse_bounded() {
121        assert_bounded([Reverse(0), Reverse(1), Reverse(!0)].iter().cloned());
122    }
123}