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}