tamata_core/
lib.rs

1use std::fmt::Debug;
2
3pub trait Fsm: Debug {
4    // Macro-generated.
5    type State: Debug;
6    type Event: Debug;
7
8    // User-provided.
9    type Context: Send + Sync;
10    type Error: Send + Sync;
11}
12
13pub trait State<F>
14where
15    F: Fsm,
16{}
17
18pub trait Event<F>
19where
20    F: Fsm,
21{}
22
23pub trait Transition<F, E>
24where
25    F: Fsm,
26    E: Event<F>,
27    Self: State<F>,
28{
29    type Next: State<F>;
30
31    fn send(self, event: E, ctx: F::Context) -> Result<Self::Next, F::Error>;
32}
33
34/// State after sending an event, and whether it is the result of a valid transition.
35///
36/// `Invalid` values can be converted to errors via `Sent::try_valid()`.
37#[derive(Debug)]
38pub enum Sent<F>
39where
40    F: Fsm,
41{
42    /// The next state was the result of a valid state transition.
43    ///
44    /// It may be identical to the previous state.
45    Valid(F::State),
46
47    /// The sent event was invalid, and the state is unchanged.
48    Invalid(F::State, F::Event),
49}
50
51impl<F> Sent<F>
52where
53    F: Fsm,
54{
55    /// Convert into current state, ignoring whether it resulted from a valid transition.
56    pub fn state(self) -> F::State {
57        match self {
58            Sent::Valid(state) => state,
59            Sent::Invalid(state, _) => state,
60        }
61    }
62
63    /// Convert `self` to a `Result`, where invalid transitions are errors.
64    pub fn try_valid(self) -> Result<F::State, Invalid<F>> {
65        match self {
66            Sent::Valid(state) => Ok(state),
67            Sent::Invalid(state, event) => {
68                let err = Invalid { state, event };
69                Err(err)
70            },
71        }
72    }
73}
74
75/// Promotion of an invalid state transition to an error.
76#[derive(Debug, thiserror::Error)]
77#[error("invalid event for state: state = {state:?}, event = {event:?}")]
78pub struct Invalid<F: Fsm> {
79    /// FSM state when the event was sent.
80    pub state: F::State,
81
82    /// Event sent to the FSM.
83    pub event: F::Event,
84}