sfsm_base/fallible.rs
1use crate::TransitGuard;
2
3/// An error type that will be returned by the state machine if something goes wrong.
4///
5/// It fulfills the same purpose that the ordinary ``` SfsmError ``` does, but allows the
6/// user to extend it with custom error types that are required by the fallible state machine.
7#[derive(Debug)]
8#[non_exhaustive]
9pub enum ExtendedSfsmError<T> {
10 /// Returned if the state machine gets stuck due to an internal error or if the state
11 /// machine has not been started before stepping.
12 Internal,
13
14 /// The custom error can be returned from the error state if an error cannot be handled.
15 /// In that case, the state machine bubbles the error up to the calling start or step
16 /// function where it then must be handled by the user.
17 Custom(T)
18}
19
20/// Trait that must be implemented by all states that are used by the fallible state machine.
21///
22/// Behaves similar to the normal ``` State ``` trait, but requires the user to specify
23/// an Error type. If this error is returned, the state machine immediately transitions into the
24/// error state.
25pub trait TryState {
26
27 // The error type that can be returned by the state
28 type Error;
29
30 /// Implement any behavior that hast to be executed when entering the state.
31 /// Return ``` Ok(()) ``` if no error occurred or ``` Err(Self::Error) ``` if something happened.
32 ///
33 /// ```rust
34 /// # use sfsm_base::fallible::TryState;
35 /// # struct FooState;
36 /// # impl TryState for FooState {
37 /// # type Error = ();
38 /// fn try_entry(&mut self) -> Result<(), Self::Error> {
39 /// println!("Called right after being transitioned into");
40 /// return Ok(());
41 /// }
42 /// # }
43 /// ```
44 fn try_entry(&mut self) -> Result<(), Self::Error> { Ok(()) }
45
46
47 /// Implement any behavior that hast to be stepping.
48 /// Return ``` Ok(()) ``` if no error occurred or ``` Err(Self::Error) ``` if something happened.
49 ///
50 /// ```rust
51 /// # use sfsm_base::fallible::TryState;
52 /// # struct FooState;
53 /// # impl TryState for FooState {
54 /// # type Error = ();
55 /// fn try_entry(&mut self) -> Result<(), Self::Error> {
56 /// println!("Called during every step");
57 /// return Ok(());
58 /// }
59 /// # }
60 /// ```
61 fn try_execute(&mut self) -> Result<(), Self::Error> { Ok(()) }
62
63
64 /// Implement any behavior that hast to be executed when exiting the state.
65 /// Return ``` Ok(()) ``` if no error occurred or ``` Err(Self::Error) ``` if something happened.
66 ///
67 /// ```rust
68 /// # use sfsm_base::fallible::TryState;
69 /// # struct FooState;
70 /// # impl TryState for FooState {
71 /// # type Error = ();
72 /// fn try_entry(&mut self) -> Result<(), Self::Error> {
73 /// println!("Called before transitioning to another state");
74 /// return Ok(());
75 /// }
76 /// # }
77 /// ```
78 fn try_exit(&mut self) -> Result<(), Self::Error> { Ok(()) }
79}
80
81/// Trait that must be implemented by all states have a transition.
82///
83/// Behaves similar to the ``` TryTransition ``` trait but errors can be returned during every
84/// call.
85pub trait TryTransition<DestinationState>: Into<DestinationState> + TryState {
86
87 /// Implement any behavior that hast to be executed when transitioning to the next the state.
88 /// Return ``` Ok(()) ``` if no error occurred or ``` Err(Self::Error) ``` if something happened.
89 ///
90 /// ```rust
91 /// # use sfsm_base::TransitGuard;
92 /// # use sfsm_base::fallible::{TryState, TryTransition};
93 /// # struct FooState;
94 /// # struct BarState;
95 /// # impl TryState for FooState {
96 /// # type Error = ();
97 /// # };
98 /// # impl Into<BarState> for FooState {
99 /// # fn into(self) -> BarState {
100 /// # BarState{}
101 /// # }
102 /// # }
103 ///
104 /// # impl TryTransition<BarState> for FooState {
105 /// fn try_action(&mut self) -> Result<(), Self::Error> {
106 /// println!("Called right after being transitioned into");
107 /// Ok(())
108 /// }
109 /// # fn guard(&self) -> TransitGuard {
110 /// # todo!()
111 /// # }
112 /// # }
113 /// ```
114 fn try_action(&mut self) -> Result<(), Self::Error> { Ok(()) }
115
116 /// Specifies when the state has to transit. Return ``` TransitGuard::Remain ``` to remain
117 /// in the current state and ``` TransitGuard::Transit ``` to transit into the next one.
118 /// This is the only function that must be implemented by the transition.
119 /// The others are optional and situational.
120 /// ```rust
121 /// # use sfsm_base::TransitGuard;
122 /// # use sfsm_base::fallible::{TryState, TryTransition};
123 /// # struct FooState;
124 /// # struct BarState;
125 /// # impl TryState for FooState {
126 /// # type Error = ();
127 /// # };
128 /// # impl Into<BarState> for FooState {
129 /// # fn into(self) -> BarState {
130 /// # BarState{}
131 /// # }
132 /// # }
133 /// #
134 /// # impl TryTransition<BarState> for FooState {
135 /// fn guard(&self) -> TransitGuard {
136 /// let foo = 0;
137 /// if foo == 0 {
138 /// TransitGuard::Remain
139 /// } else {
140 /// TransitGuard::Transit
141 /// }
142 /// }
143 /// # }
144 /// ```
145 fn guard(&self) -> TransitGuard;
146}
147
148/// This trait must be implemented by the error state.
149///
150/// The error is being injected into the error state after it has been generated and the
151/// ``` consume_error ``` function allows to specify how the incoming error should be handled.
152pub trait TryErrorState: TryState {
153
154 /// Handle the incoming error
155 /// ```rust
156 /// # use sfsm_base::fallible::{TryState, TryErrorState};
157 /// # struct ErrorState;
158 /// # impl TryState for ErrorState {
159 /// # type Error = ();
160 /// # };
161 /// #
162 /// # impl TryErrorState for ErrorState {
163 /// fn consume_error(&mut self, err: Self::Error) {
164 /// // Store it into the error trait or it
165 /// println!("Received an error: {:?}", err);
166 /// }
167 /// # }
168 ///
169 /// ```
170 fn consume_error(&mut self, err: Self::Error);
171}