1#![no_std]
2
3use core::fmt::Debug;
4
5#[cfg(feature = "inspect")]
6pub mod schema;
7
8#[cfg(feature = "inspect")]
9pub use schema::{EventSchema, Inspectable, MachineSchema, SuperstateSchema, TransitionSchema};
10
11pub trait MachineState: Copy + Eq + Debug + Send + Sync + 'static {}
13
14impl<T> MachineState for T where T: Copy + Eq + Debug + Send + Sync + 'static {}
15
16pub trait SubstateOf<Super> {}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct TransitionError<S>
36where
37 S: MachineState,
38{
39 pub from: S,
40 pub event: &'static str,
41 pub kind: TransitionErrorKind,
42}
43
44impl<S> TransitionError<S>
45where
46 S: MachineState,
47{
48 pub fn invalid_transition(from: S, event: &'static str) -> Self {
49 Self {
50 from,
51 event,
52 kind: TransitionErrorKind::InvalidTransition,
53 }
54 }
55
56 pub fn guard_failed(from: S, event: &'static str, guard: &'static str) -> Self {
57 Self {
58 from,
59 event,
60 kind: TransitionErrorKind::GuardFailed { guard },
61 }
62 }
63}
64
65#[derive(Debug, Clone, PartialEq, Eq)]
66pub enum TransitionErrorKind {
67 InvalidTransition,
68 GuardFailed { guard: &'static str },
69 ActionFailed { action: &'static str },
70}
71
72pub type TransitionResult<S> = Result<(), TransitionError<S>>;
73
74#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct GuardError {
80 pub guard: &'static str,
81 pub event: &'static str,
82 pub kind: TransitionErrorKind,
83}
84
85impl GuardError {
86 pub const fn new(guard: &'static str, event: &'static str) -> Self {
87 Self {
88 guard,
89 event,
90 kind: TransitionErrorKind::GuardFailed { guard },
91 }
92 }
93
94 pub const fn with_kind(
95 guard: &'static str,
96 event: &'static str,
97 kind: TransitionErrorKind,
98 ) -> Self {
99 Self { guard, event, kind }
100 }
101}
102
103#[derive(Debug, Clone, PartialEq, Eq)]
108pub enum DynamicError {
109 InvalidTransition {
111 from: &'static str,
112 event: &'static str,
113 },
114 GuardFailed {
116 guard: &'static str,
117 event: &'static str,
118 },
119 ActionFailed {
121 action: &'static str,
122 event: &'static str,
123 },
124 WrongState {
126 expected: &'static str,
127 actual: &'static str,
128 operation: &'static str,
129 },
130}
131
132impl DynamicError {
133 pub fn invalid_transition(from: &'static str, event: &'static str) -> Self {
134 Self::InvalidTransition { from, event }
135 }
136
137 pub fn guard_failed(guard: &'static str, event: &'static str) -> Self {
138 Self::GuardFailed { guard, event }
139 }
140
141 pub fn action_failed(action: &'static str, event: &'static str) -> Self {
142 Self::ActionFailed { action, event }
143 }
144
145 pub fn wrong_state(
146 expected: &'static str,
147 actual: &'static str,
148 operation: &'static str,
149 ) -> Self {
150 Self::WrongState {
151 expected,
152 actual,
153 operation,
154 }
155 }
156
157 pub fn from_guard_error(err: GuardError) -> Self {
159 match err.kind {
160 TransitionErrorKind::GuardFailed { guard } => Self::GuardFailed {
161 guard,
162 event: err.event,
163 },
164 TransitionErrorKind::ActionFailed { action } => Self::ActionFailed {
165 action,
166 event: err.event,
167 },
168 TransitionErrorKind::InvalidTransition => Self::InvalidTransition {
169 from: "",
170 event: err.event,
171 },
172 }
173 }
174}
175
176pub trait Machine {
177 type State: MachineState;
178
179 fn state(&self) -> Self::State;
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
183pub struct TransitionContext<S>
184where
185 S: MachineState,
186{
187 pub from: S,
188 pub to: S,
189 pub event: &'static str,
190}
191
192impl<S> TransitionContext<S>
193where
194 S: MachineState,
195{
196 pub const fn new(from: S, to: S, event: &'static str) -> Self {
197 Self { from, to, event }
198 }
199}
200
201#[derive(Debug, Clone, Copy, PartialEq, Eq)]
202pub enum AroundStage {
203 Before,
204 AfterSuccess,
205}
206
207#[derive(Debug, Clone)]
208pub enum AroundOutcome<S>
209where
210 S: MachineState,
211{
212 Proceed,
213 Abort(TransitionError<S>),
214}
215
216#[derive(Debug, Clone)]
217pub struct TransitionDefinition<S>
218where
219 S: MachineState,
220{
221 pub sources: &'static [S],
222 pub target: S,
223 pub guards: &'static [&'static str],
224 pub unless: &'static [&'static str],
225 pub before: &'static [&'static str],
226 pub after: &'static [&'static str],
227 pub around: &'static [&'static str],
228}
229
230#[derive(Debug, Clone)]
231pub struct EventDefinition<S>
232where
233 S: MachineState,
234{
235 pub name: &'static str,
236 pub guards: &'static [&'static str],
237 pub before: &'static [&'static str],
238 pub after: &'static [&'static str],
239 pub around: &'static [&'static str],
240 pub payload: Option<&'static str>,
241 pub transitions: &'static [TransitionDefinition<S>],
242}
243
244#[derive(Debug, Clone)]
245pub struct SuperstateDefinition<S>
246where
247 S: MachineState,
248{
249 pub name: &'static str,
250 pub descendants: &'static [S],
251 pub initial: S,
252}
253
254#[derive(Debug, Clone)]
255pub struct MachineDefinition<S>
256where
257 S: MachineState,
258{
259 pub name: &'static str,
260 pub states: &'static [S],
261 pub initial: S,
262 pub async_mode: bool,
263 pub superstates: &'static [SuperstateDefinition<S>],
264 pub events: &'static [EventDefinition<S>],
265}