automata_like_programming/simple_impl/series/
mod.rs

1/// Builder like implementation for creating linked sequences of states. Modifies passed
2/// instances on the fly.
3pub mod definer;
4pub mod builder;
5
6/// Simplifies creation of series by creating states based on provided iterator and connects them coninously starting from root.
7/// Returns all states created in the process. Function can be passed to be executed at any default state switch (when no states
8/// from series can be matched). Function to be executed while switching states can also be provided. Most useful for long patterns.
9/// !!! WARNING Won't create returning connections for matched starting patterns (starting elements existing in further parts of
10/// matched pattern meanining that new match could be possible while current match is still being processed).
11/// # Examples
12/// ```
13/// use std::{cell::RefCell, rc::Rc};
14/// use automata_like_programming::{
15///     series,
16///     automaton::Automaton,
17///     automaton_state::new_shared_concrete_state,
18///     simple_impl::simple_state::{
19///         KeyProvidingData,
20///         SimpleInterStateConnection,
21///         SimpleStateImplementation,
22///     }
23/// };
24/// # pub fn enumerated_char_matcher(c: char) -> impl Fn(&(usize, char)) -> bool {
25/// #     move |k: &(usize, char)| k.1 == c
26/// # }
27/// # pub struct MatchListCopiedTestData<T> {
28/// #     iter: usize,
29/// #     values: Vec<T>,
30/// #     matches: Vec<usize>,
31/// # }
32/// # 
33/// # impl <T: Copy> MatchListCopiedTestData<T> {
34/// #     pub fn new(values: Vec<T>) -> Self {
35/// #         Self { iter: 0, values, matches: Vec::new() }
36/// #     }
37/// # 
38/// #     pub fn set_match(&mut self, match_end: usize) -> () {
39/// #         self.matches.push(match_end);
40/// #     }
41/// # 
42/// #     pub fn matches(&self) -> &Vec<usize> {
43/// #         &self.matches
44/// #     }
45/// # }
46/// # 
47/// # impl <T: Copy> KeyProvidingData<(usize, T)> for MatchListCopiedTestData<T> {
48/// #     fn next_key(&mut self) -> Option<(usize,T)> {
49/// #         let current_iter = self.iter;
50/// #         let ret = self.values.get(self.iter);
51/// #         self.iter += 1;
52/// #         if let Some(c) = ret {
53/// #             return Option::Some((current_iter,*c))
54/// #         }
55/// #         Option::None
56/// #     }
57/// # }
58/// 
59/// let mut automaton = Automaton::new({
60/// let root: Rc<RefCell<SimpleStateImplementation<'_, (usize, char), u8, MatchListCopiedTestData<char>, String>>> = new_shared_concrete_state(SimpleStateImplementation::new(0));
61/// let a2: Rc<RefCell<SimpleStateImplementation<'_, (usize, char), u8, MatchListCopiedTestData<char>, String>>> = new_shared_concrete_state(SimpleStateImplementation::new(4));
62/// 
63/// let defined_states = series!(
64///                         // Iterator for generating states
65///                         "abb".chars(),
66///                         // Root node which will be the start of the series
67///                         root,
68///                         // Generator for matchers - creates matchers for enumerated elements from iterator
69///                         enumerated_char_matcher,
70///                         // Id generator - creates id values to be assigned to states
71///                         |i, _| i as u8
72///                      );
73/// assert_eq!(defined_states.len(), 3);
74/// defined_states.get(2).unwrap().borrow_mut().register_connection(
75///     SimpleInterStateConnection::new(enumerated_char_matcher('a'),
76///     |data, k| {
77///         data.set_match(k.0);
78///         Result::Ok(())
79///     },
80///     &a2));
81/// defined_states.get(2).unwrap().borrow_mut().register_connection(
82///     SimpleInterStateConnection::new_no_action(enumerated_char_matcher('a'), defined_states.get(0).unwrap())
83/// );
84/// a2.borrow_mut().register_connection(SimpleInterStateConnection::new_no_action_always_matched(&root));
85/// root.borrow_mut().register_connection(SimpleInterStateConnection::new_no_action_always_matched(&root));
86/// root
87/// });
88/// // Searched pattern starts at index 2 and ends on index 5 (abba).
89/// let mut data = MatchListCopiedTestData::new("aaabbaba".chars().collect());
90/// let automaton_result = automaton.run(&mut data);
91/// assert!(automaton_result.is_empty_iter());
92/// // Found one match.
93/// assert_eq!(data.matches().len(), 1);
94/// // Found match ending on 5th character.
95/// assert_eq!(*data.matches().get(0).unwrap(), 5);
96/// ```
97#[macro_export]
98macro_rules! series {
99    ($iter:expr, $root:ident, $matcher_gen:ident, $id_gen:expr) => {
100        $crate::series!($iter, $root, $matcher_gen, $id_gen, |_,_| {Result::Ok(())})
101    };
102    ($iter:expr, $root:ident, $matcher_gen:ident, $id_gen:expr, $default_exec:expr) => {
103        $crate::series!($iter, $root, $matcher_gen, $id_gen, |_,_| {Result::Ok(())}, |_,_| {Result::Ok(())})
104    };
105    ($iter:expr, $root:ident, $matcher_gen:ident, $id_gen:expr, $default_exec:expr, $inter_state_exec:expr) => {
106        {
107            let mut defined_states = Vec::new();
108            let mut definer = $crate::simple_impl::series::definer::SeriesDefiner::new(&$root, $default_exec);
109            for x in $iter.enumerate() {
110                let state = $crate::automaton_state::new_shared_concrete_state(SimpleStateImplementation::new(($id_gen)(x.0, x.1)));
111                definer = definer.next_state_exec(($matcher_gen)(x.1), &state, $inter_state_exec);
112                defined_states.push(state);
113            }
114            defined_states
115        }
116    };
117}
118
119#[cfg(test)]
120mod tests {
121    use std::{cell::RefCell, rc::Rc};
122
123    use crate::{automaton::Automaton, automaton_state::new_shared_concrete_state, simple_impl::simple_state::{SimpleInterStateConnection, SimpleStateImplementation}, test_commons::{enumerated_char_matcher, MatchListCopiedTestData}};
124
125    #[test]
126    fn series_from_string() -> () {
127        let mut automaton = Automaton::new({
128            let root: Rc<RefCell<SimpleStateImplementation<'_, (usize, char), u8, MatchListCopiedTestData<char>, String>>> = new_shared_concrete_state(SimpleStateImplementation::new(0));
129            let a2: Rc<RefCell<SimpleStateImplementation<'_, (usize, char), u8, MatchListCopiedTestData<char>, String>>> = new_shared_concrete_state(SimpleStateImplementation::new(4));
130
131            let defined_states = series!(
132                                                                                // Iterator for generating states
133                                                                                "abb".chars(),
134                                                                                // Root node which will be the start of the series
135                                                                                root,
136                                                                                // Generator for matchers - creates matchers for enumerated elements from iterator
137                                                                                enumerated_char_matcher,
138                                                                                // Id generator - creates id values to be placed in states
139                                                                                |i, _| i as u8);
140            assert_eq!(defined_states.len(), 3);
141            defined_states.get(2).unwrap().borrow_mut().register_connection(SimpleInterStateConnection::new(enumerated_char_matcher('a'), |data, k| {
142                data.set_match(k.0);
143                Result::Ok(())
144            }, &a2));
145            defined_states.get(2).unwrap().borrow_mut().register_connection(SimpleInterStateConnection::new_no_action(enumerated_char_matcher('a'), defined_states.get(0).unwrap()));
146            a2.borrow_mut().register_connection(SimpleInterStateConnection::new_no_action_always_matched(&root));
147            root.borrow_mut().register_connection(SimpleInterStateConnection::new_no_action_always_matched(&root));
148            root
149        });
150        let mut data = MatchListCopiedTestData::new("aaabbaba".chars().collect());
151        let automaton_result = automaton.run(&mut data);
152        assert!(automaton_result.is_empty_iter());
153        assert_eq!(data.matches().len(), 1);
154        assert_eq!(*data.matches().get(0).unwrap(), 5);
155    }
156}