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
16enum Advance<A: Address> {
17    Continue,
18    PhaseChanged,
19    Stop(Exit<A>),
20}
21
22pub struct Machine<A: Address, S, M, P, E> {
23    state: S,
24    phase: P,
25    on: fn(P, &mut S, &M) -> Result<Move<P>, E>,
26    held: VecDeque<M>,
27    address: core::marker::PhantomData<A>,
28}
29
30impl<A, S, M, P, E> crate::BehaviorBase for Machine<A, S, M, P, E>
31where
32    A: Address,
33    P: Copy + PartialEq,
34{
35    type Base = Self;
36
37    fn base(&self) -> &Self {
38        self
39    }
40}
41
42impl<A: Address, S, M, P: Copy + PartialEq, E> Machine<A, S, M, P, E> {
43    #[must_use]
44    pub fn new(state: S, phase: P, on: fn(P, &mut S, &M) -> Result<Move<P>, E>) -> Self {
45        Self {
46            state,
47            phase,
48            on,
49            held: VecDeque::new(),
50            address: core::marker::PhantomData,
51        }
52    }
53
54    #[must_use]
55    pub fn state(&self) -> &S {
56        &self.state
57    }
58
59    #[must_use]
60    pub fn phase(&self) -> P {
61        self.phase
62    }
63
64    #[must_use]
65    pub fn held(&self) -> usize {
66        self.held.len()
67    }
68
69    fn advance(&mut self, message: M) -> Result<Advance<A>, E> {
70        Ok(match (self.on)(self.phase, &mut self.state, &message)? {
71            Move::Stay => Advance::Continue,
72            Move::Defer => {
73                self.held.push_back(message);
74                Advance::Continue
75            }
76            Move::Stop => Advance::Stop(Exit::Normal),
77            Move::Goto(next) => {
78                let changed = next != self.phase;
79                self.phase = next;
80                if changed {
81                    Advance::PhaseChanged
82                } else {
83                    Advance::Continue
84                }
85            }
86        })
87    }
88
89    fn drain(&mut self) -> Result<Step<Never, Exit<A>>, E> {
90        let mut batch: VecDeque<M> = self.held.drain(..).collect();
91        while let Some(message) = batch.pop_front() {
92            let outcome = match self.advance(message) {
93                Ok(transition) => transition,
94                Err(error) => {
95                    self.held.extend(batch);
96                    return Err(error);
97                }
98            };
99            match outcome {
100                Advance::Continue => {}
101                Advance::PhaseChanged => batch.extend(self.held.drain(..)),
102                Advance::Stop(exit) => {
103                    self.held.extend(batch);
104                    return Ok(Step::Stop(exit));
105                }
106            }
107        }
108        Ok(Step::Continue)
109    }
110}
111
112impl<A, S, M, P, E> Behavior for Machine<A, S, M, P, E>
113where
114    A: Address,
115    P: Copy + PartialEq,
116{
117    type Addr = A;
118    type Msg = M;
119    type Event = User<A, M>;
120    type Sends = Vec<Never>;
121    type Ph = Never;
122    type Error = E;
123    type Birth = NoBirths;
124
125    fn init(
126        &mut self,
127        _: crate::InitializationTurn,
128    ) -> Result<Actions<A, Never, Self::Sends, NoBirths>, E> {
129        Ok(Actions::cont())
130    }
131
132    fn transition(
133        &mut self,
134        _: crate::ActiveTurn,
135        event: Self::Event,
136    ) -> Result<Actions<A, Never, Self::Sends, NoBirths>, E> {
137        match self.advance(event.message)? {
138            Advance::Stop(exit) => Ok(Actions::stop(exit)),
139            Advance::PhaseChanged => Ok(Actions::just(self.drain()?)),
140            Advance::Continue => Ok(Actions::cont()),
141        }
142    }
143}