1use 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}