Skip to main content

karpal_core/
comonad_store.rs

1use crate::hkt::HKT;
2#[cfg(any(feature = "std", feature = "alloc"))]
3use crate::hkt::StoreF;
4
5/// ComonadStore: a comonad with a notion of position and peeking.
6///
7/// Laws:
8/// - `peek(pos(wa), wa) == extract(wa)` (peeking at current position is extract)
9pub trait ComonadStore<S>: HKT {
10    fn pos<A>(wa: &Self::Of<A>) -> S;
11    fn peek<A>(s: S, wa: &Self::Of<A>) -> A;
12
13    /// Extract the focused value (equivalent to `peek(pos(wa), wa)`).
14    fn extract<A>(wa: &Self::Of<A>) -> A
15    where
16        S: Clone,
17    {
18        Self::peek(Self::pos(wa), wa)
19    }
20}
21
22#[cfg(any(feature = "std", feature = "alloc"))]
23impl<S: Clone + 'static> ComonadStore<S> for StoreF<S> {
24    fn pos<A>(wa: &(Box<dyn Fn(S) -> A>, S)) -> S {
25        wa.1.clone()
26    }
27
28    fn peek<A>(s: S, wa: &(Box<dyn Fn(S) -> A>, S)) -> A {
29        (wa.0)(s)
30    }
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36
37    #[test]
38    fn store_pos() {
39        let w: (Box<dyn Fn(i32) -> String>, i32) = (Box::new(|s| format!("value_{}", s)), 42);
40        assert_eq!(StoreF::<i32>::pos(&w), 42);
41    }
42
43    #[test]
44    fn store_peek() {
45        let w: (Box<dyn Fn(i32) -> String>, i32) = (Box::new(|s| format!("value_{}", s)), 42);
46        assert_eq!(StoreF::<i32>::peek(10, &w), "value_10");
47    }
48
49    #[test]
50    fn store_extract() {
51        let w: (Box<dyn Fn(i32) -> String>, i32) = (Box::new(|s| format!("value_{}", s)), 42);
52        assert_eq!(StoreF::<i32>::extract(&w), "value_42");
53    }
54}
55
56#[cfg(test)]
57mod law_tests {
58    use super::*;
59    use proptest::prelude::*;
60
61    proptest! {
62        // peek(pos(wa), wa) == extract(wa)
63        #[test]
64        fn store_peek_pos_is_extract(s in any::<i16>()) {
65            let w: (Box<dyn Fn(i16) -> i32>, i16) =
66                (Box::new(|s| s as i32 * 2), s);
67            let pos = StoreF::<i16>::pos(&w);
68            let left = StoreF::<i16>::peek(pos, &w);
69            let right = StoreF::<i16>::extract(&w);
70            prop_assert_eq!(left, right);
71        }
72    }
73}