automata_like_programming/
automaton.rs1use std::{marker::PhantomData, rc::Rc};
2
3use crate::automaton_state::SharedAutomatonState;
4
5pub enum NextState<'a, Id, D, E> {
7 Continue(SharedAutomatonState<'a, Id, D, E>),
9 ProcessEnded,
11 NotFound,
13}
14
15pub trait KeyIter<K> {
17 fn next(&mut self) -> Option<K>;
18}
19
20pub struct Automaton<'a, Id, D, E> {
22 start_state: SharedAutomatonState<'a, Id, D, E>,
23 _data_phantom: PhantomData<D>,
24 _error_phantom: PhantomData<E>,
25}
26
27pub enum AutomatonResult<Id, E> {
29 EmptyIter(
33 Id
34 ),
35 CouldNotFindNextState(
37 Id
38 ),
39 Error(
41 E
42 )
43}
44
45impl <Id, E> AutomatonResult<Id, E> {
46 pub fn is_empty_iter(&self) -> bool {
47 return matches!(self, AutomatonResult::EmptyIter(_))
48 }
49
50 pub fn is_could_not_find_next_state(&self) -> bool {
51 return matches!(self, AutomatonResult::CouldNotFindNextState(_))
52 }
53
54 pub fn is_error(&self) -> bool {
55 return matches!(self, AutomatonResult::Error(_))
56 }
57}
58
59impl <'a, Id, D, E> Automaton<'a, Id, D, E> {
60 pub fn new<FInit: Fn() -> SharedAutomatonState<'a, Id, D, E>>(f_state_graph_init: FInit) -> Self {
62 Self {start_state: f_state_graph_init(), _data_phantom: PhantomData{}, _error_phantom: PhantomData{}}
63 }
64
65 pub fn run(&mut self, data: &mut D) -> AutomatonResult<Id, E> {
67 let mut current_state = Rc::clone(&self.start_state);
68 loop {
69 let connection_execute_result = current_state.borrow().execute_next_connection(data);
70 match connection_execute_result {
71 Err(err) => {
72 return AutomatonResult::Error(err);
73 },
74 Ok(next_state_result) => {
75 match next_state_result {
76 NextState::Continue(next_state) => current_state = next_state,
77 NextState::NotFound => return AutomatonResult::CouldNotFindNextState(current_state.borrow().get_id_owned()),
78 NextState::ProcessEnded => return AutomatonResult::EmptyIter(current_state.borrow().get_id_owned()),
79 };
80 },
81 };
82 };
83 }
84}
85
86#[cfg(test)]
87pub mod test {
88 use std::rc::Rc;
89
90 use crate::{automaton::AutomatonResult, automaton_state::{new_shared_automaton_state, AutomatonState, SharedAutomatonState}};
91
92 use super::{Automaton, NextState};
93
94 pub struct TestNodeHello<'a> {
95 next_state: Option<SharedAutomatonState<'a, u8, String, String>>
96 }
97
98 impl<'a> TestNodeHello <'a> {
99 pub fn new(next_state: Option<SharedAutomatonState<'a, u8, String, String>>) -> Self {
100 Self { next_state }
101 }
102 }
103
104 impl <'a> AutomatonState<'a, u8, String, String> for TestNodeHello<'a> {
105 fn get_id_owned(&self) -> u8 {
106 1
107 }
108
109 fn get_id(&self) -> &u8 {
110 &1
111 }
112
113 fn execute_next_connection(&self, data: &mut String) -> Result<NextState<'a, u8, String, String>, String> {
114 data.push_str("Hello");
115 if let Option::Some(nxt_state) = &self.next_state {
116 Result::Ok(NextState::Continue(Rc::clone(nxt_state)))
117 } else {
118 Result::Ok(NextState::NotFound)
119 }
120 }
121 }
122
123 pub struct TestNodeWorld {
124 }
125
126 impl TestNodeWorld {
127 pub fn new() -> Self {
128 Self { }
129 }
130 }
131
132 impl <'a> AutomatonState<'a, u8, String, String> for TestNodeWorld {
133 fn get_id_owned(&self) -> u8 {
134 2
135 }
136
137 fn get_id(&self) -> &u8 {
138 &2
139 }
140
141 fn execute_next_connection(&self, data: &mut String) -> Result<NextState<'a, u8, String, String>, String> {
142 data.push_str(" world");
143 Result::Ok(NextState::ProcessEnded)
144 }
145 }
146
147 #[test]
148 fn automaton_2_nodes_works() -> () {
149 let mut data = String::with_capacity(11);
150 let mut automaton = Automaton::new(|| {
151 let world_state: SharedAutomatonState<u8, String, _> = new_shared_automaton_state(TestNodeWorld::new());
152 let hello_state: SharedAutomatonState<u8, String, _> = new_shared_automaton_state(TestNodeHello::new(Option::Some(Rc::clone(&world_state))));
153 hello_state
154 });
155 let run_res = automaton.run(&mut data);
156 assert!(matches!(run_res, AutomatonResult::EmptyIter(2)));
157 assert_eq!(data, "Hello world");
158 }
159
160 #[test]
161 fn automaton_result_is_empty_iter() -> () {
162 assert!(AutomatonResult::<u8, String>::EmptyIter(1).is_empty_iter());
163 assert!(!AutomatonResult::<u8, String>::CouldNotFindNextState(1).is_empty_iter());
164 assert!(!AutomatonResult::<u8, String>::Error(String::from("Test error")).is_empty_iter());
165 }
166
167 #[test]
168 fn automaton_result_is_could_not_find_next_state() -> () {
169 assert!(!AutomatonResult::<u8, String>::EmptyIter(1).is_could_not_find_next_state());
170 assert!(AutomatonResult::<u8, String>::CouldNotFindNextState(1).is_could_not_find_next_state());
171 assert!(!AutomatonResult::<u8, String>::Error(String::from("Test error")).is_could_not_find_next_state());
172 }
173
174 #[test]
175 fn automaton_result_is_error() -> () {
176 assert!(!AutomatonResult::<u8, String>::EmptyIter(1).is_error());
177 assert!(!AutomatonResult::<u8, String>::CouldNotFindNextState(1).is_error());
178 assert!(AutomatonResult::<u8, String>::Error(String::from("Test error")).is_error());
179 }
180}