fluent_state_machine/
lib.rs1mod errors;
2use errors::StateMachineError;
3
4pub struct Transition<Event, State, Store> {
5 event: Event,
6 from_state: State,
7 to_state: State,
8 before_event: fn(&mut Store),
9 after_event: fn(&mut Store),
10 condition: fn(&Store) -> bool,
11}
12
13pub struct StateMachine<Event, State, Store> {
14 global_function_after_transition: fn(&mut Store, &State, &Event),
15 transitions: Vec<Transition<Event, State, Store>>,
16 pub state: State,
17 pub store: Store,
18}
19
20pub struct StateMachineBuilder<Event, State, Store> {
41 state_machine: StateMachine<Event, State, Store>,
42 last_added_state: State,
43 errors: Vec<StateMachineError>,
44}
45
46impl<Event, State, Store> StateMachine<Event, State, Store>
47where
48 State: Copy + PartialEq,
49 Event: PartialEq,
50{
51 #[allow(clippy::needless_pass_by_value)]
53 pub fn trigger(&mut self, event: Event) {
54 for transition in &mut self.transitions {
55 if transition.event != event || self.state != transition.from_state {
57 continue;
58 }
59
60 (transition.before_event)(&mut self.store);
62
63 if (transition.condition)(&self.store) {
65 (transition.after_event)(&mut self.store);
66 self.state = transition.to_state;
67 (self.global_function_after_transition)(&mut self.store, &self.state, &event);
68 break;
69 }
70 }
71 }
72}
73
74impl<Event, State, Store> StateMachineBuilder<Event, State, Store>
75where
76 State: Copy + PartialEq,
77 Event: PartialEq,
78{
79 pub fn new(data_store: Store, initial_state: State) -> Self {
80 Self {
81 state_machine: StateMachine {
82 transitions: Vec::new(),
83 state: initial_state,
84 store: data_store,
85 global_function_after_transition: |_,_,_| {},
86 },
87 last_added_state: initial_state,
88 errors: Vec::new(),
89 }
90 }
91
92 #[must_use]
93 pub fn set_global_action(mut self, global_action: fn(&mut Store, &State, &Event)) -> Self {
94 self.state_machine.global_function_after_transition = global_action;
95 self
96 }
97
98 #[must_use]
99 pub const fn state(mut self, state: State) -> Self {
100 self.last_added_state = state;
101 self
102 }
103
104 #[must_use]
105 pub fn on(mut self, event: Event) -> Self {
106 self.state_machine.transitions.push(Transition {
107 event,
108 from_state: self.last_added_state,
109 to_state: self.last_added_state,
110 condition: |_| true,
111 before_event: |_| {},
112 after_event: |_| {},
113 });
114 self
115 }
116
117 #[must_use]
118 pub fn go_to(mut self, target: State) -> Self {
119 self.update_last_transition(|transition| transition.to_state = target);
120 self
121 }
122
123 #[must_use]
124 pub fn update(mut self, before_event: fn(&mut Store)) -> Self {
125 self.update_last_transition(|transition| transition.before_event = before_event);
126 self
127 }
128
129 #[must_use]
130 pub fn only_if(mut self, condition: fn(&Store) -> bool) -> Self {
131 self.update_last_transition(|transition| transition.condition = condition);
132 self
133 }
134
135 #[must_use]
136 pub fn then(mut self, after_event: fn(&mut Store)) -> Self {
137 self.update_last_transition(|transition| transition.after_event = after_event);
138 self
139 }
140
141 fn update_last_transition<F>(&mut self, mut update: F)
142 where
143 F: FnMut(&mut Transition<Event, State, Store>),
144 {
145 match self.state_machine.transitions.last_mut() {
146 None => self.errors.push(StateMachineError::MissingState),
147 Some(transition) => update(transition),
148 }
149 }
150
151 pub fn build(mut self) -> Result<StateMachine<Event, State, Store>, Vec<StateMachineError>> {
153 let transitions = &self.state_machine.transitions;
154
155 for i in 0..transitions.len() {
156 for j in i + 1..transitions.len() {
157 if transitions[i].event == transitions[j].event
158 && transitions[i].from_state == transitions[j].from_state
159 && transitions[i].to_state == transitions[j].to_state
160 {
161 self.errors.push(StateMachineError::DuplicateTransition);
162 }
163 }
164 }
165
166 if !self.errors.is_empty() {
167 return Err(self.errors);
168 }
169
170 Ok(self.state_machine)
171 }
172}