1use std::collections::VecDeque;
4
5use behavior::{Actions, Address, Behavior, NoBirths, User};
6use behavior::{Never, Step, Stopped};
7
8pub enum Move<P> {
9 Stay,
10 Goto(P),
11 Defer,
12 Stop,
13}
14
15#[derive(Clone, PartialEq, Eq, thiserror::Error)]
17#[error("machine rejected its mailbox input: {cause}")]
18pub struct MachineError<A, M, E> {
19 pub event: User<A, M>,
21 #[source]
23 pub cause: E,
24}
25
26impl<A, M, E: core::fmt::Debug> core::fmt::Debug for MachineError<A, M, E> {
27 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
28 formatter
29 .debug_struct("MachineError")
30 .field("event", &"<retained>")
31 .field("cause", &self.cause)
32 .finish()
33 }
34}
35
36enum Advance {
37 Continue,
38 PhaseChanged,
39 Stop,
40}
41
42pub struct Machine<A: Address, S, M, P, E> {
43 state: S,
44 phase: P,
45 on: fn(P, &mut S, &M) -> Result<Move<P>, E>,
46 held: VecDeque<M>,
47 address: core::marker::PhantomData<A>,
48}
49
50impl<A, S, M, P, E> Clone for Machine<A, S, M, P, E>
51where
52 A: Address,
53 S: Clone,
54 M: Clone,
55 P: Clone,
56{
57 fn clone(&self) -> Self {
58 Self {
59 state: self.state.clone(),
60 phase: self.phase.clone(),
61 on: self.on,
62 held: self.held.clone(),
63 address: core::marker::PhantomData,
64 }
65 }
66}
67
68impl<A, S, M, P, E> behavior::BehaviorBase for Machine<A, S, M, P, E>
69where
70 A: Address,
71{
72 type Base = Self;
73
74 fn base(&self) -> &Self {
75 self
76 }
77}
78
79impl<A: Address, S, M, P: Copy + PartialEq, E> Machine<A, S, M, P, E> {
80 #[must_use]
81 pub fn new(state: S, phase: P, on: fn(P, &mut S, &M) -> Result<Move<P>, E>) -> Self {
82 Self {
83 state,
84 phase,
85 on,
86 held: VecDeque::new(),
87 address: core::marker::PhantomData,
88 }
89 }
90
91 #[must_use]
92 pub fn state(&self) -> &S {
93 &self.state
94 }
95
96 #[must_use]
97 pub fn phase(&self) -> P {
98 self.phase
99 }
100
101 #[must_use]
102 pub fn held(&self) -> usize {
103 self.held.len()
104 }
105
106 fn advance(&mut self, message: M) -> Result<Advance, E> {
107 Ok(match (self.on)(self.phase, &mut self.state, &message)? {
108 Move::Stay => Advance::Continue,
109 Move::Defer => {
110 self.held.push_back(message);
111 Advance::Continue
112 }
113 Move::Stop => Advance::Stop,
114 Move::Goto(next) => {
115 let changed = next != self.phase;
116 self.phase = next;
117 if changed {
118 Advance::PhaseChanged
119 } else {
120 Advance::Continue
121 }
122 }
123 })
124 }
125
126 fn drain(&mut self) -> Result<Step<Never, Stopped>, E> {
127 let mut batch = core::mem::take(&mut self.held);
128 while let Some(message) = batch.pop_front() {
129 let outcome = match self.advance(message) {
130 Ok(transition) => transition,
131 Err(error) => {
132 self.held.extend(batch);
133 return Err(error);
134 }
135 };
136 match outcome {
137 Advance::Continue => {}
138 Advance::PhaseChanged => batch.extend(self.held.drain(..)),
139 Advance::Stop => {
140 self.held.extend(batch);
141 return Ok(Step::Stop(Stopped));
142 }
143 }
144 }
145 Ok(Step::Continue)
146 }
147}
148
149impl<A: Address, S, M, P, E> behavior::Protocol for Machine<A, S, M, P, E> {
150 type Addr = A;
151 type Msg = M;
152}
153
154impl<A, S, M, P, E> Behavior for Machine<A, S, M, P, E>
155where
156 A: Address,
157 S: Clone,
158 M: Clone,
159 P: Copy + PartialEq,
160{
161 type Protocol = Self;
162 type Event = User<A, M>;
163 type Sends = Vec<Never>;
164 type Ph = Never;
165 type Error = MachineError<A, M, E>;
166 type Birth = NoBirths;
167
168 fn init(
169 &mut self,
170 _: behavior::InitializationTurn,
171 ) -> Result<Actions<A, Never, Self::Sends, NoBirths>, Self::Error> {
172 Ok(Actions::cont())
173 }
174
175 fn transition(
176 &mut self,
177 _: behavior::ActiveTurn,
178 event: Self::Event,
179 ) -> Result<Actions<A, Never, Self::Sends, NoBirths>, Self::Error> {
180 let mut staged = self.clone();
181 let actions = match staged.advance(event.message.clone()) {
182 Err(cause) => return Err(MachineError { event, cause }),
183 Ok(Advance::Stop) => Actions::stop(),
184 Ok(Advance::PhaseChanged) => match staged.drain() {
185 Ok(step) => Actions::just(step),
186 Err(cause) => return Err(MachineError { event, cause }),
187 },
188 Ok(Advance::Continue) => Actions::cont(),
189 };
190 *self = staged;
191 Ok(actions)
192 }
193}