1use std::collections::HashMap;
2use std::hash::Hash;
3use std::fmt::Debug;
4use crate::types::{Transition, Effector, StreamData, StatesConnection};
5
6pub struct FSM<State, Effect>
8 where State: Eq + PartialEq + Copy + Hash,
9 Effect: Copy,
10{
11 initial_state: State,
13 transition_table: HashMap<State, Vec<Transition<State, Effect>>>,
16 post_effect: Option<Effect>
19}
20
21#[derive(Copy, Clone, Debug)]
23pub enum FSMError<'a, State>
24 where State: Eq + PartialEq + Copy + Hash + Debug
25{
26 StateDoesNotExist(State),
27 TransDoesNotExist(StatesConnection<State>),
28 NoValidTransition {
29 from: State,
30 input_data: StreamData<'a>
31 }
32}
33
34impl<State, Effect> FSM<State, Effect>
35 where State: Eq + PartialEq + Copy + Hash + Debug,
36 Effect: Copy,
37{
38 pub fn new<'a>(
43 initial_state: State,
44 transition_table: HashMap<State, Vec<Transition<State, Effect>>>,
45 post_effect: Option<Effect>
46 ) -> Result<Self, FSMError<'a, State>> {
47 if !transition_table.contains_key(&initial_state) {
48 Err(FSMError::StateDoesNotExist(initial_state))
49 } else {
50 Ok(Self {
51 initial_state,
52 transition_table,
53 post_effect
54 })
55 }
56 }
57
58 pub fn merge_effects<'a>(
66 &mut self,
67 effects_map: &HashMap<StatesConnection<State>, Vec<Effect>>
68 ) -> Result<(), FSMError<'a, State>> {
69 for (conn, effects) in effects_map.iter() {
70 if !self.transition_table.contains_key(&conn.to) {
71 return Err(FSMError::StateDoesNotExist(conn.to));
72 }
73
74 match self.transition_table.get_mut(&conn.from) {
75 Some(transitions) => {
76 let mut eff_counter: usize = 0;
77
78 for trans in transitions.iter_mut() {
79 if conn.to == trans.to {
80 trans.effect = Some(effects[eff_counter]);
81 eff_counter += 1;
82 }
83 }
84
85 if eff_counter == 0 {
86 return Err(FSMError::TransDoesNotExist(*conn));
87 }
88 },
89 None => return Err(
90 FSMError::StateDoesNotExist(conn.from)
91 )
92 }
93 }
94
95 Ok(())
96 }
97
98 pub fn proceed<'a>(
102 &self,
103 string: &'a String,
104 mut effector: Option<&'a mut dyn Effector<Effect>>
105 ) -> Result<(), FSMError<'a, State>>
106 {
107 let mut curr_state = self.initial_state;
108 let mut char_id: usize = 0;
109
110 for ch in string.chars() {
111 match self.transition_table.get(&curr_state) {
112 Some(transitions) => {
113 let mut accepted = false;
114
115 for transition in transitions.iter() {
116 match transition.transit(ch) {
117 (Some(new_state), effect) => {
118 curr_state = new_state;
119 accepted = true;
120
121 if let (Some(effector), Some(effect)) =
122 (effector.as_mut(), effect)
123 {
124 effector.dispatch(effect, StreamData {
125 string,
126 index: char_id,
127 character: ch
128 });
129 }
130
131 break;
132 },
133 _ => {}
134 }
135 }
136
137 if !accepted {
138 return Err(FSMError::NoValidTransition {
139 from: curr_state,
140 input_data: StreamData {
141 string,
142 index: char_id,
143 character: ch
144 }
145 });
146 }
147 },
148 None => {
149 return Err(FSMError::StateDoesNotExist(curr_state));
150 }
151 }
152
153 char_id += 1;
154 }
155
156 if let (Some(effector), Some(effect)) =
157 (effector, self.post_effect)
158 {
159 effector.dispatch(effect, StreamData {
160 string,
161 index: string.len(),
162 character: '\0'
163 })
164 }
165
166 Ok(())
167 }
168}