fluent_fsm/machine/
passive.rs1use std::collections::HashMap;
24use std::hash::Hash;
25
26pub struct PassiveStateMachine<TState, TModel = (), TEvent = ()>
27where
28 TState: Eq + Hash + Copy + Clone,
29 TEvent: Eq + Hash + Copy + Clone,
30{
31 running: bool,
32 current_state: TState,
33 model: TModel,
34
35 on_event: HashMap<(TState, TEvent), Vec<Box<dyn Fn(&mut TModel) + 'static + Sync + Send>>>,
36 on_enter: HashMap<TState, Vec<Box<dyn Fn(&mut TModel) + 'static + Sync + Send>>>,
37 on_leave: HashMap<TState, Vec<Box<dyn Fn(&mut TModel) + 'static + Sync + Send>>>,
38
39 transitions: HashMap<(TState, TEvent), TState>,
40}
41
42impl<TState, TModel, TEvent> PassiveStateMachine<TState, TModel, TEvent>
43where
44 TState: Eq + Hash + Copy,
45 TEvent: Eq + Hash + Copy,
46{
47 pub(crate) fn new(initial_state: TState, model: TModel) -> Self {
48 Self {
49 running: false,
50 current_state: initial_state,
51 model,
52 on_event: HashMap::new(),
53 on_enter: HashMap::new(),
54 on_leave: HashMap::new(),
55 transitions: HashMap::new(),
56 }
57 }
58
59 pub(crate) fn add_event_handler(
60 &mut self,
61 state: TState,
62 event: TEvent,
63 func: impl Fn(&mut TModel) + 'static + Sync + Send,
64 ) {
65 let key = (state, event);
66 match self.on_event.get_mut(&key) {
67 Some(vec) => {
68 vec.push(Box::new(func));
69 }
70 None => {
71 self.on_event.insert(key, vec![Box::new(func)]);
72 }
73 }
74 }
75
76 pub(crate) fn add_enter_handler(
77 &mut self,
78 state: TState,
79 func: impl Fn(&mut TModel) + 'static + Sync + Send,
80 ) {
81 match self.on_enter.get_mut(&state) {
82 Some(vec) => {
83 vec.push(Box::new(func));
84 }
85 None => {
86 self.on_enter.insert(state, vec![Box::new(func)]);
87 }
88 }
89 }
90
91 pub(crate) fn add_leave_handler(
92 &mut self,
93 state: TState,
94 func: impl Fn(&mut TModel) + 'static + Sync + Send,
95 ) {
96 match self.on_leave.get_mut(&state) {
97 Some(vec) => {
98 vec.push(Box::new(func));
99 }
100 None => {
101 self.on_leave.insert(state, vec![Box::new(func)]);
102 }
103 }
104 }
105
106 pub(crate) fn add_transition(&mut self, on: TEvent, from: TState, to: TState) {
107 self.transitions.insert((from, on), to);
108 }
109
110 pub fn current_state(&self) -> &TState {
111 &self.current_state
112 }
113
114 pub fn model(&self) -> &TModel {
115 &self.model
116 }
117
118 pub fn model_mut(&mut self) -> &mut TModel {
119 &mut self.model
120 }
121
122 pub fn start(&mut self) {
123 if self.running {
124 return;
125 }
126
127 self.running = true;
128
129 if let Some(actions) = self.on_enter.get(&(self.current_state)) {
130 for action in actions.iter() {
131 action(&mut self.model);
132 }
133 }
134 }
135
136 pub fn fire(&mut self, event: TEvent) {
137 if !self.running {
138 panic!("State machine is not running");
139 }
140
141 if let Some(handlers) = self.on_event.get(&(self.current_state, event)) {
143 for handler in handlers.iter() {
144 handler(&mut self.model);
145 }
146 }
147
148 if let Some(state) = self.transitions.get(&(self.current_state, event)) {
150 self.goto(*state);
151 }
152 }
153
154 pub(crate) fn goto(&mut self, state: TState) {
155 if let Some(actions) = self.on_leave.get(&(self.current_state)) {
156 for action in actions.iter() {
157 action(&mut self.model);
158 }
159 }
160
161 self.current_state = state;
162
163 if let Some(actions) = self.on_enter.get(&(self.current_state)) {
164 for action in actions.iter() {
165 action(&mut self.model);
166 }
167 }
168 }
169}