partial_functional/monoid/
last.rs

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