1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//! Sink.

use super::*;

impl<H: Hazard> I<H, { Dep::Helpful }> {
    /// A sink that maps and returns the data from the payload to the resolver.
    ///
    /// - Payload: Mapped to the resolver by `f`.
    /// - Resolver: Outputs the mapped value.
    ///
    /// | Interface | Ingress         |
    /// | :-------: | --------------- |
    /// |  **Fwd**  | `HOption<H::P>` |
    /// |  **Bwd**  | `H::R`          |
    pub fn sink_map(self, f: impl Fn(HOption<H::P>) -> H::R) {
        self.sink_fsm_map((), |ip, ()| (f(ip), ()))
    }

    /// A [`I::sink_map`] with an internal state.
    ///
    /// `f` additionally takes the current state and returns the next state. The state is updated when an ingress
    /// transfer happens.
    ///
    /// - Payload: Mapped to the resolver by `f`.
    /// - Resolver: Outputs the mapped value.
    ///
    /// | Interface | Ingress         |
    /// | :-------: | --------------- |
    /// |  **Fwd**  | `HOption<H::P>` |
    /// |  **Bwd**  | `H::R`          |
    pub fn sink_fsm_map<S: Copy>(self, init_state: S, f: impl Fn(HOption<H::P>, S) -> (H::R, S)) {
        // TODO: Write safety condition
        // TODO: ir is dependent on ip, so this might cause a loop if Dep >= SelfOnly
        unsafe {
            <Self as Interface>::fsm(self, init_state, |ip, (), s| {
                let (ir, s_next) = f(ip, s);

                let s_next = if ip.is_some_and(|p| H::ready(p, ir)) { s_next } else { s };

                ((), ir, s_next)
            })
        }
    }
}