1#![doc = include_str!("../README.md")]
2#![no_std]
3
4pub use edfsm_macros::impl_fsm;
5
6#[derive(Debug, Clone)]
8pub enum Input<C, E> {
9 Command(C),
10 Event(E),
11}
12
13#[derive(Debug, Clone, Copy)]
15pub enum Change {
16 Transitioned,
17 Updated,
18}
19
20pub trait Fsm {
36 type S;
38 type C;
40 type E;
42 type SE;
44
45 fn for_command(s: &Self::S, c: Self::C, se: &mut Self::SE) -> Option<Self::E>;
49
50 fn on_event(s: &mut Self::S, e: &Self::E) -> Option<Change>;
55
56 fn on_change(s: &Self::S, e: &Self::E, se: &mut Self::SE, change: Change);
60
61 fn step(s: &mut Self::S, i: Input<Self::C, Self::E>, se: &mut Self::SE) -> Option<Self::E> {
67 let e = match i {
68 Input::Command(c) => Self::for_command(s, c, se),
69 Input::Event(e) => Some(e),
70 };
71 if let Some(e) = e {
72 let r = Self::on_event(s, &e);
73 if let Some(c) = r {
74 Self::on_change(s, &e, se, c);
75 Some(e)
76 } else {
77 None
78 }
79 } else {
80 None
81 }
82 }
83}
84
85pub trait Init<S> {
94 fn init(&mut self, state: &S);
96}
97
98pub trait Terminating {
105 fn terminating(&self) -> bool;
107}
108
109pub trait Drain {
115 type Item;
117
118 fn drain_all(&mut self) -> impl Iterator<Item = Self::Item> + Send;
120}
121
122#[cfg(test)]
123mod test {
124 use super::{Change, Fsm, Input};
125
126 #[test]
127 fn test_step() {
128 struct Idle;
131 struct Running;
132 enum State {
133 Idle(Idle),
134 Running(Running),
135 }
136
137 struct Start;
138 struct Stop;
139 enum Command {
140 Start(Start),
141 Stop(Stop),
142 }
143
144 struct Started;
145 struct Stopped;
146 enum Event {
147 Started(Started),
148 Stopped(Stopped),
149 }
150
151 struct EffectHandlers {
154 started: u32,
155 stopped: u32,
156 transitioned_stopped_to_started: u32,
157 }
158
159 impl EffectHandlers {
160 pub fn start_something(&mut self) {
161 self.started += 1;
162 }
163
164 pub fn stop_something(&mut self) {
165 self.stopped += 1;
166 }
167
168 pub fn enter_running(&mut self) {
169 self.transitioned_stopped_to_started += 1;
170 }
171 }
172
173 struct MyFsm;
176
177 impl Fsm for MyFsm {
178 type S = State;
179 type C = Command;
180 type E = Event;
181 type SE = EffectHandlers;
182
183 fn for_command(s: &State, c: Command, se: &mut EffectHandlers) -> Option<Event> {
184 match (s, c) {
185 (State::Running(s), Command::Stop(c)) => {
186 Self::for_running_stop(s, c, se).map(Event::Stopped)
187 }
188 (State::Idle(s), Command::Start(c)) => {
189 Self::for_idle_start(s, c, se).map(Event::Started)
190 }
191 _ => None,
192 }
193 }
194
195 fn on_event(mut s: &mut State, e: &Event) -> Option<Change> {
196 let r = match (&mut s, e) {
197 (State::Running(s), Event::Stopped(e)) => Self::on_running_stopped(s, e)
198 .map(|new_s| (Change::Transitioned, Some(State::Idle(new_s)))),
199 (State::Idle(s), Event::Started(e)) => Self::on_idle_started(s, e)
200 .map(|new_s| (Change::Transitioned, Some(State::Running(new_s)))),
201 _ => None,
202 };
203 if let Some((c, new_s)) = r {
204 if let Some(new_s) = new_s {
205 *s = new_s;
206 }
207 Some(c)
208 } else {
209 None
210 }
211 }
212
213 fn on_change(s: &State, e: &Event, se: &mut EffectHandlers, change: Change) {
214 if let Change::Transitioned = change {
215 if let State::Running(s) = s {
219 Self::on_entry_running(s, e, se)
220 }
221 }
222 match (s, e) {
223 (State::Idle(s), Event::Stopped(e)) => Self::on_idle_stopped(s, e, se),
224 (State::Running(s), Event::Started(e)) => Self::on_running_started(s, e, se),
225 _ => (),
226 }
227 }
228 }
229
230 impl MyFsm {
231 fn on_entry_running(_to_s: &Running, _e: &Event, se: &mut EffectHandlers) {
232 se.enter_running()
233 }
234
235 fn for_running_stop(
236 _s: &Running,
237 _c: Stop,
238 _se: &mut EffectHandlers,
239 ) -> Option<Stopped> {
240 Some(Stopped)
241 }
242
243 fn on_running_started(_s: &Running, _e: &Started, se: &mut EffectHandlers) {
244 se.start_something();
245 }
246
247 fn on_running_stopped(_s: &Running, _e: &Stopped) -> Option<Idle> {
248 Some(Idle)
249 }
250
251 fn for_idle_start(_s: &Idle, _c: Start, _se: &mut EffectHandlers) -> Option<Started> {
252 Some(Started)
253 }
254
255 fn on_idle_started(_s: &Idle, _e: &Started) -> Option<Running> {
256 Some(Running)
257 }
258
259 fn on_idle_stopped(_s: &Idle, _e: &Stopped, se: &mut EffectHandlers) {
260 se.stop_something();
261 }
262 }
263
264 let mut se = EffectHandlers {
267 started: 0,
268 stopped: 0,
269 transitioned_stopped_to_started: 0,
270 };
271
272 let e = MyFsm::step(
275 &mut State::Idle(Idle),
276 Input::Command(Command::Start(Start)),
277 &mut se,
278 );
279 assert!(matches!(e, Some(Event::Started(Started))));
280 assert_eq!(se.started, 1);
281 assert_eq!(se.stopped, 0);
282 assert_eq!(se.transitioned_stopped_to_started, 1);
283
284 let e = MyFsm::step(
285 &mut State::Running(Running),
286 Input::Command(Command::Start(Start)),
287 &mut se,
288 );
289 assert!(e.is_none());
290 assert_eq!(se.started, 1);
291 assert_eq!(se.stopped, 0);
292 assert_eq!(se.transitioned_stopped_to_started, 1);
293
294 let e = MyFsm::step(
295 &mut State::Running(Running),
296 Input::Command(Command::Stop(Stop)),
297 &mut se,
298 );
299 assert!(matches!(e, Some(Event::Stopped(Stopped))));
300 assert_eq!(se.started, 1);
301 assert_eq!(se.stopped, 1);
302 assert_eq!(se.transitioned_stopped_to_started, 1);
303
304 let e = MyFsm::step(
305 &mut State::Idle(Idle),
306 Input::Command(Command::Stop(Stop)),
307 &mut se,
308 );
309 assert!(e.is_none());
310 assert_eq!(se.started, 1);
311 assert_eq!(se.stopped, 1);
312 assert_eq!(se.transitioned_stopped_to_started, 1);
313
314 let mut se = EffectHandlers {
317 started: 0,
318 stopped: 0,
319 transitioned_stopped_to_started: 0,
320 };
321
322 let e = MyFsm::step(
325 &mut State::Idle(Idle),
326 Input::Event(Event::Started(Started)),
327 &mut se,
328 );
329 assert!(matches!(e, Some(Event::Started(Started))));
330 assert_eq!(se.started, 1);
331 assert_eq!(se.stopped, 0);
332 assert_eq!(se.transitioned_stopped_to_started, 1);
333
334 let e = MyFsm::step(
335 &mut State::Running(Running),
336 Input::Event(Event::Started(Started)),
337 &mut se,
338 );
339 assert!(e.is_none());
340 assert_eq!(se.started, 1);
341 assert_eq!(se.stopped, 0);
342 assert_eq!(se.transitioned_stopped_to_started, 1);
343
344 let e = MyFsm::step(
345 &mut State::Running(Running),
346 Input::Event(Event::Stopped(Stopped)),
347 &mut se,
348 );
349 assert!(matches!(e, Some(Event::Stopped(Stopped))));
350 assert_eq!(se.started, 1);
351 assert_eq!(se.stopped, 1);
352 assert_eq!(se.transitioned_stopped_to_started, 1);
353
354 let e = MyFsm::step(
355 &mut State::Idle(Idle),
356 Input::Event(Event::Stopped(Stopped)),
357 &mut se,
358 );
359 assert!(e.is_none());
360 assert_eq!(se.started, 1);
361 assert_eq!(se.stopped, 1);
362 assert_eq!(se.transitioned_stopped_to_started, 1);
363 }
364}