elm_parser/counter/
counters.rs

1use crate::datacell::{Datacell::*, ElementCell::Prop};
2
3use super::{
4    counter_commands::CommandType, counter_instance::CounterInstance, counter_types::CounterType,
5    handle_instance::HandleInstance,
6};
7
8#[derive(Debug, Clone)]
9pub struct Counters {
10    pub counters_list: Vec<CounterInstance>,
11    pub handles_list: Vec<HandleInstance>,
12}
13
14// we need to get counter props
15// look for counter usage
16
17impl Counters {
18    pub fn new() -> Counters {
19        Counters {
20            counters_list: Vec::new(),
21            handles_list: Vec::new(),
22        }
23    }
24
25    fn iter_props(&mut self, json: &DataCell, props: &Vec<Prop>) {
26        props.iter().for_each(|prop| {
27            if CounterType::is_valid(&prop.key) {
28                let mut value_splits = prop.value.split(" ");
29                let counter_name = value_splits.next().expect("Counter must have a name");
30
31                let default_value = value_splits.next();
32                // create new counter
33                self.add_counter(CounterInstance::new(
34                    counter_name,
35                    &prop.key,
36                    json.id,
37                    default_value,
38                ));
39            }
40        })
41    }
42
43    pub fn get_counters_from_json(&mut self, json: &DataCell) {
44        match &json.cell_type {
45            CellType::Element(el) => {
46                self.iter_props(json, &el.props);
47                el.children
48                    .iter()
49                    .for_each(|child| self.get_counters_from_json(child))
50            }
51            CellType::Root(root) => root
52                .children
53                .iter()
54                .for_each(|child| self.get_counters_from_json(child)),
55            _ => (),
56        }
57    }
58
59    pub fn add_counter(&mut self, counter: CounterInstance) {
60        let counter_exists = self.counters_list.iter().any(|c| c.name == counter.name);
61        assert!(
62            !counter_exists,
63            "Counter name {} already used",
64            counter.name
65        );
66        self.counters_list.push(counter);
67    }
68
69    pub fn add_handle(&mut self, handle: HandleInstance) {
70        let handle_exists = self.handles_list.iter().any(|c| c.name == handle.name);
71        assert!(!handle_exists, "handle {} already assigned", handle.name);
72        self.handles_list.push(handle);
73    }
74
75    pub fn remove_counter(&mut self, counter: &CounterInstance) {
76        self.counters_list = self
77            .counters_list
78            .iter()
79            .filter(|c| c.name != counter.name)
80            .cloned()
81            .collect();
82    }
83
84    pub fn execute(
85        &mut self,
86        command_type: CommandType,
87        counter_name: &str,
88        handle_name: &Option<String>,
89    ) -> Option<String> {
90        let counter = self
91            .counters_list
92            .iter_mut()
93            .find(|c| c.name == counter_name);
94        assert!(
95            !counter.is_none(),
96            "Counter {counter_name} Does not exist or is out of scope"
97        );
98
99        match command_type {
100            CommandType::INC => counter.unwrap().increment(),
101            CommandType::DEC => counter.unwrap().decrement(),
102            CommandType::ASSIGN => {
103                if let Some(handle_name) = handle_name {
104                    let handle_exists = self.handles_list.iter().any(|c| &c.name == handle_name);
105                    assert!(!handle_exists, "handle {} already assigned", handle_name);
106                    self.handles_list.push(HandleInstance {
107                        name: handle_name.to_string(),
108                        value: counter.unwrap().current_value.to_string(),
109                    });
110                }
111            }
112            CommandType::INSERT => {
113                return Some(counter.unwrap().current_value.to_string());
114            }
115        }
116        None
117    }
118
119    pub fn check_scope(&self, block_cell: &DataCell, counter_name: &str, json_tree: &DataCell) {
120        let counter = self.counters_list.iter().find(|c| c.name == counter_name);
121        assert!(
122            !counter.is_none(),
123            "Counter {counter_name} Does not exist or is out of scope"
124        );
125
126        // we need to see if block_cell is child of element with id counter.scope
127        let mut parents_list = Vec::new();
128        self.search_el(block_cell, json_tree, &mut parents_list);
129
130        assert!(
131            parents_list.contains(&counter.unwrap().scope),
132            "Counter {counter_name} is out of scope"
133        );
134    }
135
136    fn search_el(
137        &self,
138        block_cell: &DataCell,
139        json_tree: &DataCell,
140        parents_list: &mut Vec<usize>,
141    ) -> bool {
142        match &json_tree.cell_type {
143            CellType::Block(_) => json_tree.id == block_cell.id,
144            CellType::Element(el) => {
145                parents_list.push(json_tree.id.try_into().unwrap());
146
147                for child in el.children.iter() {
148                    if self.search_el(block_cell, child, parents_list) {
149                        return true;
150                    }
151                }
152
153                parents_list.pop();
154                return false;
155            }
156            CellType::Root(el) => {
157                parents_list.push(json_tree.id.try_into().unwrap());
158
159                for child in el.children.iter() {
160                    if self.search_el(block_cell, child, parents_list) {
161                        return true;
162                    }
163                }
164
165                parents_list.pop();
166                return false;
167            }
168            _ => false,
169        }
170    }
171}