partial_functional/monoid/
product.rs

1use num_traits;
2
3use crate::semigroup::Semigroup;
4
5/// Semigroup of the Product of type T if type T implements num_traits::Num.
6/// ```
7/// # use partial_functional::prelude::*;
8/// let five = Product(5);
9/// let ten = Product(10);
10/// assert_eq!(Product(50), five.combine(ten));
11/// ```
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
13pub struct Product<T>(pub T);
14
15impl<T: Semigroup + num_traits::Num> Default for Product<T> {
16    fn default() -> Self {
17        Self(num_traits::identities::One::one())
18    }
19}
20
21impl<T: PartialEq> PartialEq<T> for Product<T> {
22    fn eq(&self, other: &T) -> bool {
23        self.0 == *other
24    }
25}
26
27impl<T: PartialOrd> PartialOrd<T> for Product<T> {
28    fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
29        self.0.partial_cmp(other)
30    }
31}
32impl<T> From<T> for Product<T> {
33    fn from(value: T) -> Self {
34        Self(value)
35    }
36}
37
38impl<T: std::ops::Mul<Output = T>> Semigroup for Product<T> {
39    fn combine(self, rhs: Self) -> Self {
40        Self(self.0 * rhs.0)
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use crate::monoid::Monoid;
47
48    use super::*;
49
50    use quickcheck::{Arbitrary, Gen, TestResult};
51    use quickcheck_macros::quickcheck;
52
53    impl Arbitrary for Product<u32> {
54        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
55            Product(u8::arbitrary(g).into())
56        }
57
58        fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
59            Box::new(u32::shrink(&self.0).map(|x| x.into()))
60        }
61    }
62
63    #[quickcheck]
64    fn identity_property() {
65        assert_eq!(Product::<u32>(1), Product::empty())
66    }
67
68    fn property_product_of_vec_is_same_as_product_combine(vec: Vec<u8>) -> TestResult {
69        if vec.len() < 2 {
70            return TestResult::discard();
71        }
72
73        let left: Product<u128> = vec
74            .iter()
75            .copied()
76            .map(|x| x as u128)
77            .product::<u128>()
78            .into();
79        let right = vec
80            .iter()
81            .copied()
82            .map(|x| Product::from(x as u128))
83            .fold(Product::default(), |a, x| a.combine(x));
84
85        TestResult::from_bool(left == right)
86    }
87
88    #[test]
89    fn product_of_vec_is_same_as_product_combine() {
90        let gen = Gen::new(15);
91        let mut qtest = quickcheck::QuickCheck::new().gen(gen);
92
93        qtest.quickcheck(property_product_of_vec_is_same_as_product_combine as fn(Vec<u8>) -> TestResult);
94    }
95
96    #[quickcheck]
97    fn associativity_property(x: Product<u32>, y: Product<u32>, z: Product<u32>) -> bool {
98        x.combine(y.combine(z)) == x.combine(y).combine(z)
99    }
100}