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