rs_state_machine/core/errors.rs
1use std::fmt;
2use std::fmt::Debug;
3use super::transition::Transition;
4
5/// Represents an error with a Transition.
6#[derive(Debug)]
7pub struct TransitionError<S, E>
8where
9 S: Eq,
10 E: Eq,
11{
12 /// The type of the error.
13 error_type: TransitionErrorType,
14 /// The transition that caused the error.
15 pub transition: Transition<S, E>,
16}
17
18/// Classifies the types of [TransitionError]s that can happen in a [Machine](super::machine::Machine).
19///
20/// Types are currently only used to specify the display information of an error.
21#[derive(Debug, Clone)]
22pub enum TransitionErrorType {
23 // Definition Errors
24
25 /// The transition already exists in the [Machine](super::machine::Machine).
26 AlreadyExists,
27 /// Another transition with the same input & event exists, thus preventing to ensure which output state will be selected.
28 NondeterministicTransition,
29
30 // Running Errors
31
32 /// The transition cannot be applied. Can be explained by a missing transition definition, wrong event, wrong input state.
33 CannotApply,
34 /// The transition's guard does not allow the transition to be applied.
35 NotAllowed,
36}
37
38impl<S, E> TransitionError<S, E>
39where
40 S: Eq + Copy,
41 E: Eq + Copy,
42{
43 /// Creates a new [`TransitionError`] of type [`TransitionErrorType::AlreadyExists`] from the given:
44 /// * `input` - the input state of the duplicated transition
45 /// * `event` - the event of the duplicated transition
46 /// * `output` - the output state of the duplicated transition
47 pub fn already_exists(input: S, event: E, output: S) -> TransitionError<S, E> {
48 Self {
49 error_type: TransitionErrorType::AlreadyExists,
50 transition: Transition::new(input, event, output),
51 }
52 }
53
54 /// Creates a new [`TransitionError`] of type [`TransitionErrorType::NondeterministicTransition`] from the given:
55 /// * `input` - the input state of the nondeterministic transition
56 /// * `event` - the event of the nondeterministic transition
57 /// * `output` - the output state of the nondeterministic transition
58 pub fn nondeterministic(input: S, event: E, output: S) -> TransitionError<S, E> {
59 Self {
60 error_type: TransitionErrorType::NondeterministicTransition,
61 transition: Transition::new(input, event, output),
62 }
63 }
64
65 /// Creates a new [`TransitionError`] of type [`TransitionErrorType::CannotApply`] from the given:
66 /// * `input` - input state of the error'd transaction
67 /// * `event` - event of the error'd transaction
68 pub fn cannot_apply(input: S, event: E) -> TransitionError<S, E> {
69 Self {
70 error_type: TransitionErrorType::CannotApply,
71 transition: Transition::new(input, event, input), // todo should not re-use input
72 }
73 }
74
75 /// Creates a new [`TransitionError`] of type [`TransitionErrorType::NotAllowed`] from the given:
76 /// * `input` - the input state of the not allowed transition
77 /// * `event` - the event of the not allowed transition
78 /// * `output` - the output state of the not allowed transition
79 pub fn not_allowed(input: S, event: E, output: S) -> TransitionError<S, E> {
80 Self {
81 error_type: TransitionErrorType::NotAllowed,
82 transition: Transition::new(input, event, output),
83 }
84 }
85
86}
87
88impl<S, E> fmt::Display for TransitionError<S, E>
89where
90 S: Eq + Debug,
91 E: Eq + Debug,
92{
93 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94 match &self.error_type {
95 TransitionErrorType::AlreadyExists => {
96 write!(f, "Transition {:?} is already defined in this State Machine (no duplicates).", self.transition)
97 }
98 TransitionErrorType::NondeterministicTransition => {
99 write!(f, "Two different transitions exist with [input={:?}, event={:?}], leading to non-deterministic state machine", self.transition.state_in, self.transition.event)
100 }
101 TransitionErrorType::CannotApply => {
102 write!(f, "Cannot apply [event={:?}] on [input_state={:?}] (unknown transition)", self.transition.event, self.transition.state_in)
103 }
104 TransitionErrorType::NotAllowed => {
105 write!(f, "Cannot apply [transition={:?}], the guard function does not allow it", self.transition)
106 }
107 //_ => write!(f, "Generic TransitionError with {:?}", self.transition)
108 }
109 }
110}