1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use std::collections::HashMap;
use std::hash::Hash;
use std::fmt::Debug;
use crate::types::{Transition, Effector};
pub struct FSM<State, Effect>
where State: Eq + PartialEq + Copy + Hash,
Effect: Eq + PartialEq + Copy,
{
initial_state: State,
transition_table: HashMap<State, Vec<Transition<State, Effect>>>,
}
#[derive(Copy, Clone, Debug)]
pub enum FSMError<'a, State>
where State: Eq + PartialEq + Copy + Debug
{
StateDoesNotExist(State),
NoValidTransition {
from: State,
string: &'a String,
index: usize,
character: char
}
}
impl<State, Effect> FSM<State, Effect>
where State: Eq + PartialEq + Copy + Hash + Debug,
Effect: Eq + PartialEq + Copy,
{
pub fn new<'a>(
initial_state: State,
transition_table: HashMap<State, Vec<Transition<State, Effect>>>
) -> Result<Self, FSMError<'a, State>> {
if !transition_table.contains_key(&initial_state) {
Err(FSMError::StateDoesNotExist(initial_state))
} else {
Ok(Self {
initial_state,
transition_table
})
}
}
pub fn proceed<'a>(
&self,
string: &'a String,
mut effector: Option<&'a mut dyn Effector<Effect>>
) -> Result<(), FSMError<'a, State>>
{
let mut curr_state = self.initial_state;
let mut char_id: usize = 0;
for ch in string.chars() {
match self.transition_table.get(&curr_state) {
Some(transitions) => {
let mut accepted = false;
for transition in transitions.iter() {
match transition.transit(ch) {
(Some(new_state), effect) => {
curr_state = new_state;
accepted = true;
if let (Some(effector), Some(effect)) =
(effector.as_mut(), effect)
{
effector.dispatch(effect);
}
break;
},
_ => {}
}
}
if !accepted {
return Err(FSMError::NoValidTransition {
from: curr_state,
string,
index: char_id,
character: ch
});
}
},
None => {
return Err(FSMError::StateDoesNotExist(curr_state));
}
}
char_id += 1;
}
Ok(())
}
}