game_state_machine/
lib.rs1#![deny(missing_docs)]
6
7pub enum StateTransition<S> {
11 None,
13 Pop,
16 Push(Box<dyn State<S>>),
18 Switch(Box<dyn State<S>>),
20 Quit,
22}
23
24pub trait State<S> {
29 fn on_start(&mut self, _state_data: &mut S) {}
31 fn on_stop(&mut self, _state_data: &mut S) {}
33 fn on_pause(&mut self, _state_data: &mut S) {}
35 fn on_resume(&mut self, _state_data: &mut S) {}
37 fn update(&mut self, _state_data: &mut S) -> StateTransition<S> {
42 StateTransition::None
43 }
44}
45
46pub struct StateMachine<S> {
54 state_stack: Vec<Box<dyn State<S>>>,
55}
56
57impl<S> Default for StateMachine<S> {
58 fn default() -> Self {
59 Self {
60 state_stack: Vec::default(),
61 }
62 }
63}
64
65impl<S> StateMachine<S> {
66 pub fn is_running(&self) -> bool {
68 !self.state_stack.is_empty()
69 }
70
71 pub fn update(&mut self, state_data: &mut S) {
74 let trans = match self.state_stack.last_mut() {
75 Some(state) => state.update(state_data),
76 None => StateTransition::None,
77 };
78
79 self.transition(trans, state_data);
80 }
81
82 fn transition(&mut self, request: StateTransition<S>, state_data: &mut S) {
83 match request {
84 StateTransition::None => (),
85 StateTransition::Pop => self.pop(state_data),
86 StateTransition::Push(state) => self.push(state, state_data),
87 StateTransition::Switch(state) => self.switch(state, state_data),
88 StateTransition::Quit => self.stop(state_data),
89 }
90 }
91
92 fn switch(&mut self, mut state: Box<dyn State<S>>, state_data: &mut S) {
93 if let Some(mut state) = self.state_stack.pop() {
94 state.on_stop(state_data)
95 }
96
97 state.on_start(state_data);
98 self.state_stack.push(state);
99 }
100
101 pub fn push(&mut self, mut state: Box<dyn State<S>>, state_data: &mut S) {
104 if let Some(state) = self.state_stack.last_mut() {
105 state.on_pause(state_data);
106 }
107
108 state.on_start(state_data);
109 self.state_stack.push(state);
110 }
111
112 fn pop(&mut self, state_data: &mut S) {
113 if let Some(mut state) = self.state_stack.pop() {
114 state.on_stop(state_data);
115 }
116
117 if let Some(state) = self.state_stack.last_mut() {
118 state.on_resume(state_data);
119 }
120 }
121
122 pub fn stop(&mut self, state_data: &mut S) {
124 while let Some(mut state) = self.state_stack.pop() {
125 state.on_stop(state_data);
126 }
127 }
128}
129#[cfg(test)]
130mod tests {
131 use crate::*;
132
133 type StateData = (isize, isize);
134
135 pub struct Test;
136
137 impl State<StateData> for Test {
138 fn on_start(&mut self, data: &mut StateData) {
139 data.0 += data.1;
140 }
141
142 fn on_resume(&mut self, data: &mut StateData) {
143 self.on_start(data);
144 }
145
146 fn update(&mut self, _data: &mut StateData) -> StateTransition<StateData> {
147 StateTransition::Push(Box::new(Test))
148 }
149 }
150
151 #[test]
152 fn sm_test() {
153 let mut sm = StateMachine::<StateData>::default();
154
155 let mut state_data = (0, 10);
156
157 sm.push(Box::new(Test), &mut state_data);
158 assert!(state_data.0 == 10);
159
160 sm.update(&mut state_data);
161 assert!(state_data.0 == 20);
162
163 sm.stop(&mut state_data);
164 assert!(state_data.0 == 20);
165 assert!(!sm.is_running())
166 }
167}