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}