Skip to main content

behavior/
machine.rs

1//! A finite-state behavior derived solely from receive and become.
2
3use std::collections::VecDeque;
4
5use crate::Exit;
6use crate::behavior::{Actions, Address, Behavior, NoBirths, User};
7use crate::next::{Never, Step};
8
9pub enum Move<P> {
10    Stay,
11    Goto(P),
12    Defer,
13    Stop,
14}
15
16pub struct Machine<A: Address, S, M, P, E> {
17    state: S,
18    phase: P,
19    on: fn(P, &mut S, &M) -> Result<Move<P>, E>,
20    held: VecDeque<M>,
21    address: core::marker::PhantomData<A>,
22}
23
24impl<A: Address, S, M, P: Copy + PartialEq, E> Machine<A, S, M, P, E> {
25    #[must_use]
26    pub fn new(state: S, phase: P, on: fn(P, &mut S, &M) -> Result<Move<P>, E>) -> Self {
27        Self {
28            state,
29            phase,
30            on,
31            held: VecDeque::new(),
32            address: core::marker::PhantomData,
33        }
34    }
35
36    #[must_use]
37    pub fn state(&self) -> &S {
38        &self.state
39    }
40
41    #[must_use]
42    pub fn phase(&self) -> P {
43        self.phase
44    }
45
46    #[must_use]
47    pub fn held(&self) -> usize {
48        self.held.len()
49    }
50
51    fn advance(&mut self, message: M) -> Result<(Step<Never, Exit<A>>, bool), E> {
52        Ok(match (self.on)(self.phase, &mut self.state, &message)? {
53            Move::Stay => (Step::Continue, false),
54            Move::Defer => {
55                self.held.push_back(message);
56                (Step::Continue, false)
57            }
58            Move::Stop => (Step::Stop(Exit::Normal), false),
59            Move::Goto(next) => {
60                let changed = next != self.phase;
61                self.phase = next;
62                (Step::Continue, changed)
63            }
64        })
65    }
66
67    fn drain(&mut self) -> Result<Step<Never, Exit<A>>, E> {
68        let mut batch: VecDeque<M> = self.held.drain(..).collect();
69        while let Some(message) = batch.pop_front() {
70            let (verdict, changed) = self.advance(message)?;
71            if let Step::Stop(exit) = verdict {
72                self.held.extend(batch);
73                return Ok(Step::Stop(exit));
74            }
75            if changed {
76                batch.extend(self.held.drain(..));
77            }
78        }
79        Ok(Step::Continue)
80    }
81}
82
83impl<A, S, M, P, E> Behavior for Machine<A, S, M, P, E>
84where
85    A: Address,
86    P: Copy + PartialEq,
87{
88    type Addr = A;
89    type Msg = M;
90    type Event = User<A, M>;
91    type Sends = Vec<Never>;
92    type Ph = Never;
93    type Error = E;
94    type Birth = NoBirths;
95
96    fn init(&mut self) -> Result<Actions<A, Never, Self::Sends, NoBirths>, E> {
97        Ok(Actions::cont())
98    }
99
100    fn transition(
101        &mut self,
102        event: Self::Event,
103    ) -> Result<Actions<A, Never, Self::Sends, NoBirths>, E> {
104        let (verdict, changed) = self.advance(event.message)?;
105        match verdict {
106            Step::Stop(exit) => Ok(Actions::stop(exit)),
107            _ if changed => Ok(Actions::just(self.drain()?)),
108            _ => Ok(Actions::cont()),
109        }
110    }
111}