partial_functional/monoid/
max.rs

1use crate::semigroup::Semigroup;
2use num_traits::Bounded;
3
4/// Semigroup over the Maximum of T if T implements [std::cmp::Ord].
5/// ```
6/// # use partial_functional::{Max, Semigroup};
7/// assert_eq!(Max(10), Max(10).combine(Max(5)));
8/// ```
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
10pub struct Max<T>(pub T);
11
12impl<T: Default + Semigroup + Bounded> Default for Max<T> {
13    fn default() -> Self {
14        Self(Bounded::min_value())
15    }
16}
17
18impl<T: PartialEq> PartialEq<T> for Max<T> {
19    fn eq(&self, other: &T) -> bool {
20        self.0 == *other
21    }
22}
23
24impl<T: PartialOrd> PartialOrd<T> for Max<T> {
25    fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
26        self.0.partial_cmp(other)
27    }
28}
29
30impl<T> From<T> for Max<T> {
31    fn from(value: T) -> Self {
32        Self(value)
33    }
34}
35
36impl<T: Ord> Semigroup for Max<T> {
37    fn combine(self, rhs: Self) -> Self {
38        Self(self.0.max(rhs.0))
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use crate::monoid::Monoid;
45
46    use super::*;
47
48    use quickcheck::Arbitrary;
49    use quickcheck_macros::quickcheck;
50
51    impl Arbitrary for Max<u32> {
52        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
53            Max(u32::arbitrary(g).into())
54        }
55
56        fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
57            Box::new(u32::shrink(&self.0).map(|x| x.into()))
58        }
59    }
60
61    #[quickcheck]
62    fn identity_property() {
63        assert_eq!(Max::<u32>(u32::MIN), Max::empty())
64    }
65
66    #[quickcheck]
67    fn max_of_vec_is_same_as_max_combine(vec: Vec<Max<u32>>) -> bool {
68        let left: Max<u32> = vec
69            .iter()
70            .copied()
71            .map(|x| x.0)
72            .max()
73            .unwrap_or(u32::MIN)
74            .into();
75        let right = vec
76            .iter()
77            .copied()
78            .fold(Max::default(), |a, x| a.combine(x));
79
80        left == right
81    }
82
83    #[quickcheck]
84    fn associativity_property(x: Max<u32>, y: Max<u32>, z: Max<u32>) -> bool {
85        x.combine(y.combine(z)) == x.combine(y).combine(z)
86    }
87}