1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
use core::fmt::Debug;

use crate::Response;
use crate::State;
use crate::StateExt;
use crate::Superstate;

/// A data structure that declares the types associated with the state machine.
pub trait StateMachine
where
    Self: Sized,
{
    /// Event that is processed by the state machine.
    type Event;

    /// Enumeration of the various states.
    type State: State<Self>;

    /// Enumeration of the various superstates.
    type Superstate<'a>: Superstate<Self>
    where
        Self::State: 'a;

    /// Initial state of the state machine.
    const INIT_STATE: Self::State;

    /// Method that is called *before* an event is dispatched to a state or
    /// superstate handler.
    fn on_dispatch(&mut self, _state: StateOrSuperstate<'_, '_, Self>, _event: &Self::Event) {}

    /// Method that is called *after* every transition.
    fn on_transition(&mut self, _source: &Self::State, _target: &Self::State) {}
}

/// A state machine where the context is of type `Self`.
pub trait StateMachineContext: StateMachine {
    /// Create an uninitialized state machine. Use [UninitializedStateMachine::init] to initialize it.
    fn state_machine(self) -> UninitializedStateMachine<Self>
    where
        Self: Sized,
    {
        UninitializedStateMachine {
            context: self,
            state: Self::INIT_STATE,
        }
    }
}

impl<T> StateMachineContext for T where T: StateMachine {}

/// A state machine that has not yet been initialized.
///
/// A state machine needs to be initialized before it can handle events. This
/// can be done by calling the [`init`](Self::init) method on it. This will
/// execute all the entry actions into the initial state.
pub struct UninitializedStateMachine<O>
where
    O: StateMachine,
{
    context: O,
    state: <O as StateMachine>::State,
}

impl<O> UninitializedStateMachine<O>
where
    O: StateMachine,
{
    /// Initialize the state machine by excecuting all entry actions towards
    /// the initial state.
    ///
    /// ```
    /// # use statig::prelude::*;
    /// # #[derive(Default)]
    /// # pub struct Blinky {
    /// #     led: bool,
    /// # }
    /// #
    /// # pub struct Event;
    /// #
    /// # impl StateMachine for Blinky {
    /// #     type State = State;
    /// #     
    /// #     type Superstate<'a> = ();
    /// #     
    /// #     type Event = Event;
    /// #     
    /// #     const INIT_STATE: State = State::on();
    /// # }
    /// #
    /// # #[state_machine]
    /// # impl Blinky {
    /// #     #[state]
    /// #     fn on(event: &Event) -> Response<State> { Handled }
    /// # }
    /// #
    /// let uninitialized_state_machine = Blinky::default().state_machine();
    ///
    /// // The uninitialized state machine is consumed to create the initialized
    /// // state machine.
    /// let initialized_state_machine = uninitialized_state_machine.init();
    /// ```
    pub fn init(self) -> InitializedStatemachine<O> {
        let mut state_machine: InitializedStatemachine<O> = InitializedStatemachine {
            context: self.context,
            state: self.state,
        };
        state_machine.init();
        state_machine
    }
}

/// A state machine that has been initialized.
pub struct InitializedStatemachine<M>
where
    M: StateMachine,
{
    context: M,
    state: <M as StateMachine>::State,
}

impl<M> InitializedStatemachine<M>
where
    M: StateMachine,
{
    /// Get an immutable reference to the current state of the state machine.
    pub fn state(&self) -> &<M as StateMachine>::State {
        &self.state
    }

    /// Get a mutable reference the current state of the state machine.
    ///
    /// # Safety
    ///
    /// Mutating the state externally could break the state machines internal
    /// invariants.
    pub unsafe fn state_mut(&mut self) -> &mut <M as StateMachine>::State {
        &mut self.state
    }

    /// Handle the given event.
    pub fn handle(&mut self, event: &M::Event) {
        let response = self.state.handle(&mut self.context, event);

        match response {
            Response::Super => {}
            Response::Handled => {}
            Response::Transition(state) => self.transition(state),
        }
    }

    /// Initialize the state machine by excecuting all entry actions towards the initial state.
    fn init(&mut self) {
        let enter_levels = self.state.depth();
        self.state.enter(&mut self.context, enter_levels);
    }

    /// Transition from the current state to the given target state.
    fn transition(&mut self, mut target: <M as StateMachine>::State) {
        // Get the transition path we need to perform from one state to the next.
        let (exit_levels, enter_levels) = self.state.transition_path(&mut target);

        // Perform the exit from the previous state towards the common ancestor state.
        self.state.exit(&mut self.context, exit_levels);

        // Update the state.
        core::mem::swap(&mut self.state, &mut target);

        // Perform the entry actions from the common ancestor state into the new state.
        self.state.enter(&mut self.context, enter_levels);

        <M as StateMachine>::on_transition(&mut self.context, &target, &self.state);
    }
}

impl<M> Default for InitializedStatemachine<M>
where
    M: StateMachine + Default,
{
    fn default() -> Self {
        Self {
            context: <M as Default>::default(),
            state: <M as StateMachine>::INIT_STATE,
        }
    }
}

impl<M> core::ops::Deref for InitializedStatemachine<M>
where
    M: StateMachine,
{
    type Target = M;

    fn deref(&self) -> &Self::Target {
        &self.context
    }
}

impl<M> core::ops::DerefMut for InitializedStatemachine<M>
where
    M: StateMachine,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.context
    }
}

/// Holds a reference to either a state or superstate.
pub enum StateOrSuperstate<'a, 'b, M: StateMachine>
where
    M::State: 'b,
{
    /// Reference to a state.
    State(&'a M::State),
    /// Reference to a superstate.
    Superstate(&'a M::Superstate<'b>),
}

impl<'a, 'b, M: StateMachine> core::fmt::Debug for StateOrSuperstate<'a, 'b, M>
where
    M::State: Debug,
    M::Superstate<'b>: Debug,
{
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::State(state) => f.debug_tuple("State").field(state as &dyn Debug).finish(),
            Self::Superstate(superstate) => f
                .debug_tuple("Superstate")
                .field(superstate as &dyn Debug)
                .finish(),
        }
    }
}