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}