squads_rustfsm_trait/
lib.rs1use std::{
2 error::Error,
3 fmt::{Debug, Display, Formatter},
4};
5
6pub trait StateMachine: Sized {
11 type Error: Error;
13 type State;
15 type SharedState;
17 type Event;
19 type Command;
21
22 fn on_event(
25 &mut self,
26 event: Self::Event,
27 ) -> Result<Vec<Self::Command>, MachineError<Self::Error>>;
28
29 fn name(&self) -> &str;
30
31 fn state(&self) -> &Self::State;
33 fn set_state(&mut self, new_state: Self::State);
34
35 fn shared_state(&self) -> &Self::SharedState;
37
38 fn has_reached_final_state(&self) -> bool;
40
41 fn from_parts(state: Self::State, shared: Self::SharedState) -> Self;
43
44 fn visualizer() -> &'static str;
46}
47
48#[derive(Debug)]
50pub enum MachineError<E: Error> {
51 InvalidTransition,
53 Underlying(E),
55}
56
57impl<E: Error> From<E> for MachineError<E> {
58 fn from(e: E) -> Self {
59 Self::Underlying(e)
60 }
61}
62
63impl<E: Error> Display for MachineError<E> {
64 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
65 match self {
66 MachineError::InvalidTransition => f.write_str("Invalid transition"),
67 MachineError::Underlying(e) => Display::fmt(&e, f),
68 }
69 }
70}
71impl<E: Error> Error for MachineError<E> {}
72
73pub enum MachineUpdate<Machine>
74where
75 Machine: StateMachine,
76{
77 InvalidTransition,
78 Ok { commands: Vec<Machine::Command> },
79}
80
81impl<M> MachineUpdate<M>
82where
83 M: StateMachine,
84{
85 pub fn unwrap(self) -> Vec<M::Command> {
87 match self {
88 Self::Ok { commands } => commands,
89 Self::InvalidTransition => panic!("Transition was not successful!"),
90 }
91 }
92}
93
94pub enum TransitionResult<Machine, DestinationState>
96where
97 Machine: StateMachine,
98 DestinationState: Into<Machine::State>,
99{
100 InvalidTransition,
103 Ok {
105 commands: Vec<Machine::Command>,
106 new_state: DestinationState,
107 },
108 Err(Machine::Error),
110}
111
112impl<Sm, Ds> TransitionResult<Sm, Ds>
113where
114 Sm: StateMachine,
115 Ds: Into<Sm::State>,
116{
117 pub fn ok<CI>(commands: CI, new_state: Ds) -> Self
120 where
121 CI: IntoIterator<Item = Sm::Command>,
122 {
123 Self::Ok {
124 commands: commands.into_iter().collect(),
125 new_state,
126 }
127 }
128
129 pub fn from<CurrentState>(current_state: CurrentState) -> Self
132 where
133 CurrentState: Into<Ds>,
134 {
135 let as_dest: Ds = current_state.into();
136 Self::Ok {
137 commands: vec![],
138 new_state: as_dest,
139 }
140 }
141}
142
143impl<Sm, Ds> TransitionResult<Sm, Ds>
144where
145 Sm: StateMachine,
146 Ds: Into<Sm::State> + Default,
147{
148 pub fn commands<CI>(commands: CI) -> Self
150 where
151 CI: IntoIterator<Item = Sm::Command>,
152 {
153 Self::Ok {
154 commands: commands.into_iter().collect(),
155 new_state: Ds::default(),
156 }
157 }
158}
159
160impl<Sm, Ds> Default for TransitionResult<Sm, Ds>
161where
162 Sm: StateMachine,
163 Ds: Into<Sm::State> + Default,
164{
165 fn default() -> Self {
166 Self::Ok {
167 commands: vec![],
168 new_state: Ds::default(),
169 }
170 }
171}
172
173impl<Sm, Ds> TransitionResult<Sm, Ds>
174where
175 Sm: StateMachine,
176 Ds: Into<Sm::State>,
177{
178 pub fn into_general(self) -> TransitionResult<Sm, Sm::State> {
180 match self {
181 TransitionResult::InvalidTransition => TransitionResult::InvalidTransition,
182 TransitionResult::Ok {
183 commands,
184 new_state,
185 } => TransitionResult::Ok {
186 commands,
187 new_state: new_state.into(),
188 },
189 TransitionResult::Err(e) => TransitionResult::Err(e),
190 }
191 }
192
193 #[allow(clippy::type_complexity)]
196 pub fn into_cmd_result(self) -> Result<(Vec<Sm::Command>, Sm::State), MachineError<Sm::Error>> {
197 let general = self.into_general();
198 match general {
199 TransitionResult::Ok {
200 new_state,
201 commands,
202 } => Ok((commands, new_state)),
203 TransitionResult::InvalidTransition => Err(MachineError::InvalidTransition),
204 TransitionResult::Err(e) => Err(MachineError::Underlying(e)),
205 }
206 }
207}