automata_like_programming/simple_impl/series/
definer.rs

1use std::{rc::Rc, sync::Arc};
2
3use crate::simple_impl::simple_state::{KeyProvidingData, SharedSimpleState, SimpleInterStateConnection};
4
5/// Allows for quick definition of chain of states that follow single path.
6/// # Examples
7/// ```
8/// # use std::{cell::RefCell, rc::Rc};
9/// # use automata_like_programming::{
10/// #   automaton::{
11/// #     AutomatonResult
12/// #   }, 
13/// #   automaton_state::{
14/// #     new_shared_concrete_state,
15/// #     AutomatonState
16/// #   }, 
17/// #   simple_impl::{
18/// #     series::definer::SeriesDefiner,
19/// #     simple_state::{
20/// #       KeyProvidingData,
21/// #       SimpleStateImplementation
22/// #     }
23/// #   }
24/// # };
25/// #
26/// # fn char_matcher(c: char) -> impl Fn(&char) -> bool {
27/// #   move |k: &char| *k == c
28/// # }
29/// #
30/// # pub struct TestData {}
31/// #
32/// # impl KeyProvidingData<char> for TestData {
33/// #   fn next_key(&mut self) -> Option<char> {
34/// #     Option::Some('a')
35/// #   }
36/// # }
37/// #
38/// // Creates series of state that will match 'abc' character sequence or go back to root state anytime there is a mismatch.
39/// fn create_abc_series_state_tree() -> Rc<RefCell<dyn AutomatonState<'static, char, TestData, String>>> {
40///   let root_state = new_shared_concrete_state(SimpleStateImplementation::new('x'));
41///   SeriesDefiner::new_without_default_action(&root_state)
42///   .next_state(char_matcher('a'), &new_shared_concrete_state(SimpleStateImplementation::new('a')))
43///   .next_state(char_matcher('b'), &new_shared_concrete_state(SimpleStateImplementation::new('b')))
44///   .next_state(char_matcher('c'), &new_shared_concrete_state(SimpleStateImplementation::new('c')));
45///   root_state
46/// }
47/// ```
48pub struct SeriesDefiner<'a, K, Id: Copy, D: KeyProvidingData<K>, E> {
49    default_state: SharedSimpleState<'a, K, Id, D, E>,
50    default_execution: Arc<dyn Fn(&mut D, &K) -> Result<(), E> + 'a>,
51    // default_execution: FDExec,
52    state: SharedSimpleState<'a, K, Id, D, E>,
53}
54
55impl <'a, K, Id: Copy, D: KeyProvidingData<K>, E> SeriesDefiner<'a, K, Id, D, E> {
56    /// Creates new `SeriesDefiner` which defaults unmatched connections to the same node it starts from.
57    pub fn new_without_default_action(starting_state: &SharedSimpleState<'a, K, Id, D, E>) -> SeriesDefiner<'a, K, Id, D, E> {
58        Self::new(starting_state, |_, _| {Result::Ok(())})
59    }
60
61    /// Creates new `SeriesDefiner` which defaults unmatched connections to the same node it starts from.
62    pub fn new<FDExec: Fn(&mut D, &K) -> Result<(), E> + 'a>(starting_state: &SharedSimpleState<'a, K, Id, D, E>, default_execution_function: FDExec) -> SeriesDefiner<'a, K, Id, D, E> {
63        Self::new_different_default_state(starting_state, starting_state, default_execution_function)
64    }
65
66    /// Creates new `SeriesDefiner` with possible different starting and default states.
67    pub fn new_different_default_state<FDExec: Fn(&mut D, &K) -> Result<(), E> + 'a>(starting_state: &SharedSimpleState<'a, K, Id, D, E>, default_state: &SharedSimpleState<'a, K, Id, D, E>, default_execution_function: FDExec) -> SeriesDefiner<'a, K, Id, D, E> {
68        SeriesDefiner {
69            state: Rc::clone(&starting_state),
70            default_state: Rc::clone(&default_state),
71            default_execution: Arc::new(default_execution_function),
72        }
73    }
74    
75    /// Adds connection to currently processed state. No function is executed when changing state. Creates a default connection 
76    /// to starting state as well.
77    pub fn next_state<M>(mut self, matcher: M, next_state: &SharedSimpleState<'a, K, Id, D, E>) -> SeriesDefiner<'a, K, Id, D, E> 
78    where M: 'a + Fn(&K) -> bool
79    {
80        self.state.borrow_mut().register_connection(SimpleInterStateConnection::new_no_action(matcher, next_state));
81        let default_exec_function = Arc::clone(&self.default_execution);
82        self.state.borrow_mut().register_connection(SimpleInterStateConnection::new_always_matched(move |k,d| (default_exec_function)(k, d), &self.default_state));
83        self.state = Rc::clone(next_state);
84        self
85    }
86
87    /// Adds connection to currently processed state. Given function is executed when changing state. Creates a default connection 
88    /// to starting state as well.
89    pub fn next_state_exec<M, FExec>(mut self, matcher: M, next_state: &SharedSimpleState<'a, K, Id, D, E>, execution_function: FExec) -> SeriesDefiner<'a, K, Id, D, E> 
90    where
91    M: 'a + Fn(&K) -> bool,
92    FExec: 'a + Fn(&mut D, &K) -> Result<(), E>
93    {
94        self.state.borrow_mut().register_connection(SimpleInterStateConnection::new(matcher, execution_function, next_state));
95        let default_exec_function = Arc::clone(&self.default_execution);
96        self.state.borrow_mut().register_connection(SimpleInterStateConnection::new_always_matched(move |k,d| (default_exec_function)(k, d), &self.default_state));
97        self.state = Rc::clone(next_state);
98        self
99    }
100}
101
102#[cfg(test)]
103mod test {
104    use std::{cell::RefCell, rc::Rc};
105
106    use crate::{automaton::{Automaton, AutomatonResult}, automaton_state::{new_shared_concrete_state, AutomatonState}, simple_impl::simple_state::SimpleStateImplementation, test_commons::{char_matcher, unwrap_result, CopiedTestData}};
107
108    use super::SeriesDefiner;
109
110    fn create_abc_series_state_tree() -> Rc<RefCell<dyn AutomatonState<'static, char, CopiedTestData<char>, String>>> {
111        let root_state = new_shared_concrete_state(SimpleStateImplementation::new('x'));
112        SeriesDefiner::new(&root_state, |_, _| {Result::Ok(())})
113        .next_state(char_matcher('a'), &new_shared_concrete_state(SimpleStateImplementation::new('a')))
114        .next_state(char_matcher('b'), &new_shared_concrete_state(SimpleStateImplementation::new('b')))
115        .next_state(char_matcher('c'), &new_shared_concrete_state(SimpleStateImplementation::new('c')));
116        root_state
117    }
118
119    #[test]
120    fn series_full_match() -> () {
121        let mut automaton = Automaton::new(create_abc_series_state_tree());
122        let mut data = CopiedTestData::new(vec!['a', 'b', 'c']);
123        let automaton_result: AutomatonResult<char, String> = automaton.run(&mut data);
124        assert_eq!(unwrap_result!(automaton_result.expect_empty_iter()), 'c');
125    }
126
127    #[test]
128    fn series_back_to_default() -> () {
129        let mut automaton = Automaton::new(create_abc_series_state_tree());
130        let mut data = CopiedTestData::new(vec!['a', 'b', 'd']);
131        let automaton_result: AutomatonResult<char, String> = automaton.run(&mut data);
132        assert_eq!(unwrap_result!(automaton_result.expect_empty_iter()), 'x');
133    }
134
135    #[test]
136    fn series_no_more_sates() -> () {
137        let mut automaton = Automaton::new(create_abc_series_state_tree());
138        let mut data = CopiedTestData::new(vec!['a', 'b', 'c', 'd']);
139        let automaton_result = automaton.run(&mut data).expect_could_not_find_next_state();
140        assert_eq!(unwrap_result!(automaton_result), 'c');
141    }
142}