rust_sfsm/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]
2
3pub use rust_sfsm_macros::rust_sfsm;
4
5/// # Trait for the state behavior.
6///
7/// This trait should be implemented for an `enum`
8/// representing a set of states.
9///
10/// ## Example
11///
12/// ```rust
13/// /// List of protocol states.
14/// #[derive(Clone, Copy, Default, PartialEq)]
15/// enum States {
16/// #[default]
17/// Init,
18/// Opened,
19/// Closed,
20/// Locked,
21/// }
22///
23/// /// List of protocol events.
24/// enum Events {
25/// Create,
26/// Open,
27/// Close,
28/// Lock,
29/// Unlock,
30/// }
31///
32/// /// Protocol state machine context (data shared between states).
33/// #[derive(Default)]
34/// struct Context {
35/// lock_counter: u16,
36/// }
37///
38/// impl StateBehavior for States {
39/// type State = Self;
40/// type Event<'a> = Events;
41/// type Context = Context;
42///
43/// fn enter(&self, _context: &mut Self::Context) {
44/// if self == &States::Locked {
45/// _context.lock_counter += 1
46/// }
47/// }
48///
49/// fn handle_event(
50/// &self,
51/// event: &Self::Event<'_>,
52/// _context: &mut Self::Context,
53/// ) -> Option<Self::State> {
54/// match (self, event) {
55/// (&States::Init, &Events::Create) => Some(States::Opened),
56/// (&States::Opened, &Events::Close) => Some(States::Closed),
57/// (&States::Closed, &Events::Open) => Some(States::Opened),
58/// (&States::Closed, &Events::Lock) => Some(States::Locked),
59/// (&States::Locked, &Events::Unlock) => Some(States::Closed),
60/// _ => None,
61/// }
62/// }
63/// }
64/// ```
65pub trait StateBehavior {
66 type State: Clone + Copy + PartialEq + Default;
67 type Event<'a>
68 where
69 Self: 'a;
70 type Context;
71
72 /// Handle an event and return the next state (if a transition occurs).
73 fn handle_event(
74 &self,
75 event: &Self::Event<'_>,
76 _context: &mut Self::Context,
77 ) -> Option<Self::State>;
78
79 /// State entry.
80 fn enter(&self, _context: &mut Self::Context) {}
81
82 /// State exit.
83 fn exit(&self, _context: &mut Self::Context) {}
84}
85
86/// # Trait for the state machine behavior.
87///
88/// This trait is implemented by the [rust_sfsm] attribute macro
89/// and shouldn't be manually implemented by the user.
90///
91/// It may be used to monomorphize different types implementing
92/// the state machine behavior for a given set of states.
93///
94/// ## Example
95///
96/// ```rust
97/// fn test_state_machine<S: StateMachine<States>>(state_machine: &mut S) {
98/// assert!(state_machine.current_state() == States::Init);
99///
100/// state_machine.handle_event(&Events::Create);
101/// assert!(state_machine.current_state() == States::Opened);
102///
103/// state_machine.handle_event(&Events::Close);
104/// assert!(state_machine.current_state() == States::Closed);
105///
106/// state_machine.handle_event(&Events::Lock);
107/// assert!(state_machine.current_state() == States::Locked);
108///
109/// state_machine.handle_event(&Events::Unlock);
110/// assert!(state_machine.current_state() == States::Closed);
111///
112/// state_machine.handle_event(&Events::Open);
113/// assert!(state_machine.current_state() == States::Opened);
114/// }
115/// ```
116pub trait StateMachine<S: StateBehavior> {
117 /// Get the current state.
118 fn current_state(&self) -> S::State;
119
120 /// Handle an event and transit if necessary.
121 fn handle_event(&mut self, event: &S::Event<'_>);
122
123 /// Transit to a new state.
124 fn transit(&mut self, new_state: S::State);
125
126 /// Force transition to a new state without calls to respectives
127 /// `enter` and `exit` functions.
128 fn force_state(&mut self, new_state: S::State);
129}