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)]
105pub struct CallbackError<E> {
106 pub action: &'static str,
107 pub event: &'static str,
108 pub source: E,
109}
110
111impl<E> CallbackError<E> {
112 pub fn new(action: &'static str, event: &'static str, source: E) -> Self {
113 Self {
114 action,
115 event,
116 source,
117 }
118 }
119}
120
121#[derive(Debug, Clone, PartialEq, Eq)]
123pub enum EventError<E> {
124 Guard(GuardError),
125 Callback(CallbackError<E>),
126}
127
128impl<E> EventError<E> {
129 pub const fn guard(err: GuardError) -> Self {
130 Self::Guard(err)
131 }
132
133 pub fn callback(action: &'static str, event: &'static str, source: E) -> Self {
134 Self::Callback(CallbackError::new(action, event, source))
135 }
136}
137
138#[doc(hidden)]
139pub trait FallibleCallbackReturn<E> {
140 fn into_result(self) -> Result<(), E>;
141}
142
143impl<E> FallibleCallbackReturn<E> for () {
144 fn into_result(self) -> Result<(), E> {
145 Ok(())
146 }
147}
148
149impl<E> FallibleCallbackReturn<E> for Result<(), E> {
150 fn into_result(self) -> Result<(), E> {
151 self
152 }
153}
154
155#[derive(Debug, Clone, PartialEq, Eq)]
160pub enum DynamicError<E = ()> {
161 InvalidTransition {
163 from: &'static str,
164 event: &'static str,
165 },
166 GuardFailed {
168 guard: &'static str,
169 event: &'static str,
170 },
171 ActionFailed {
173 action: &'static str,
174 event: &'static str,
175 },
176 CallbackFailed {
178 action: &'static str,
179 event: &'static str,
180 source: E,
181 },
182 WrongState {
184 expected: &'static str,
185 actual: &'static str,
186 operation: &'static str,
187 },
188}
189
190impl<E> DynamicError<E> {
191 pub fn invalid_transition(from: &'static str, event: &'static str) -> Self {
192 Self::InvalidTransition { from, event }
193 }
194
195 pub fn guard_failed(guard: &'static str, event: &'static str) -> Self {
196 Self::GuardFailed { guard, event }
197 }
198
199 pub fn action_failed(action: &'static str, event: &'static str) -> Self {
200 Self::ActionFailed { action, event }
201 }
202
203 pub fn callback_failed(action: &'static str, event: &'static str, source: E) -> Self {
204 Self::CallbackFailed {
205 action,
206 event,
207 source,
208 }
209 }
210
211 pub fn wrong_state(
212 expected: &'static str,
213 actual: &'static str,
214 operation: &'static str,
215 ) -> Self {
216 Self::WrongState {
217 expected,
218 actual,
219 operation,
220 }
221 }
222
223 pub fn from_guard_error(err: GuardError) -> Self {
225 match err.kind {
226 TransitionErrorKind::GuardFailed { guard } => Self::GuardFailed {
227 guard,
228 event: err.event,
229 },
230 TransitionErrorKind::ActionFailed { action } => Self::ActionFailed {
231 action,
232 event: err.event,
233 },
234 TransitionErrorKind::InvalidTransition => Self::InvalidTransition {
235 from: "",
236 event: err.event,
237 },
238 }
239 }
240
241 pub fn from_event_error(err: EventError<E>) -> Self {
242 match err {
243 EventError::Guard(err) => Self::from_guard_error(err),
244 EventError::Callback(err) => Self::callback_failed(err.action, err.event, err.source),
245 }
246 }
247}
248
249pub trait Machine {
250 type State: MachineState;
251
252 fn state(&self) -> Self::State;
253}
254
255#[derive(Debug, Clone, Copy, PartialEq, Eq)]
256pub struct TransitionContext<S>
257where
258 S: MachineState,
259{
260 pub from: S,
261 pub to: S,
262 pub event: &'static str,
263}
264
265impl<S> TransitionContext<S>
266where
267 S: MachineState,
268{
269 pub const fn new(from: S, to: S, event: &'static str) -> Self {
270 Self { from, to, event }
271 }
272}
273
274#[derive(Debug, Clone, Copy, PartialEq, Eq)]
275pub enum AroundStage {
276 Before,
277 AfterSuccess,
278}
279
280#[derive(Debug, Clone)]
281pub enum AroundOutcome<S>
282where
283 S: MachineState,
284{
285 Proceed,
286 Abort(TransitionError<S>),
287}
288
289#[derive(Debug, Clone)]
290pub struct TransitionDefinition<S>
291where
292 S: MachineState,
293{
294 pub sources: &'static [S],
295 pub target: S,
296 pub guards: &'static [&'static str],
297 pub unless: &'static [&'static str],
298 pub before: &'static [&'static str],
299 pub after: &'static [&'static str],
300 pub around: &'static [&'static str],
301}
302
303#[derive(Debug, Clone)]
304pub struct EventDefinition<S>
305where
306 S: MachineState,
307{
308 pub name: &'static str,
309 pub guards: &'static [&'static str],
310 pub before: &'static [&'static str],
311 pub after: &'static [&'static str],
312 pub around: &'static [&'static str],
313 pub payload: Option<&'static str>,
314 pub transitions: &'static [TransitionDefinition<S>],
315}
316
317#[derive(Debug, Clone)]
318pub struct SuperstateDefinition<S>
319where
320 S: MachineState,
321{
322 pub name: &'static str,
323 pub descendants: &'static [S],
324 pub initial: S,
325}
326
327#[derive(Debug, Clone)]
328pub struct MachineDefinition<S>
329where
330 S: MachineState,
331{
332 pub name: &'static str,
333 pub states: &'static [S],
334 pub initial: S,
335 pub async_mode: bool,
336 pub superstates: &'static [SuperstateDefinition<S>],
337 pub events: &'static [EventDefinition<S>],
338}