hawktracer_parser/
registry_updater.rs

1use crate::event::DataType;
2use crate::event::Event;
3use crate::event_klass::EventKlass;
4use crate::registry::CoreEventKlassId;
5use crate::registry::EventKlassRegistry;
6
7pub struct RegistryUpdater<'a> {
8    registry: &'a mut EventKlassRegistry,
9}
10
11impl<'a> RegistryUpdater<'a> {
12    pub fn new(registry: &'a mut EventKlassRegistry) -> RegistryUpdater<'a> {
13        RegistryUpdater { registry }
14    }
15
16    pub fn update_registry_from_event(&mut self, event: &Event) -> Result<(), &'static str> {
17        match event.get_klass_id() {
18            x if x == CoreEventKlassId::KlassInfo as u32 => self.add_new_klass(&event),
19            x if x == CoreEventKlassId::FieldInfo as u32 => self.add_klass_field(&event),
20            _ => Err("Klass id is neither KlassInfo nor FieldInfo"),
21        }
22    }
23
24    fn add_new_klass(&mut self, event: &Event) -> Result<(), &'static str> {
25        let klass_id = match event.get_value_u32("info_klass_id") {
26            Ok(value) => value,
27            Err(_) => return Err("Cannot read klass id"),
28        };
29
30        if CoreEventKlassId::is_core_klass(klass_id) {
31            return Ok(());
32        }
33
34        let klass_name = match event.get_value_string("event_klass_name") {
35            Ok(value) => value.clone(),
36            Err(_) => return Err("Cannot read klass name"),
37        };
38
39        self.registry
40            .add_klass(EventKlass::new(klass_id, klass_name));
41        Ok(())
42    }
43
44    fn add_klass_field(&mut self, event: &Event) -> Result<(), &'static str> {
45        let klass_id = match event.get_value_u32("info_klass_id") {
46            Ok(value) => value,
47            Err(_) => return Err("Cannot read klass id"),
48        };
49
50        if CoreEventKlassId::is_core_klass(klass_id) {
51            return Ok(()); // Ignore core fields
52        }
53
54        let field_name = match event.get_value_string("field_name") {
55            Ok(value) => value.clone(),
56            Err(_) => return Err("Cannot read field name"),
57        };
58
59        let type_name = match event.get_value_string("field_type") {
60            Ok(value) => value.clone(),
61            Err(_) => return Err("Cannot read field type"),
62        };
63
64        let data_type = match event.get_value_u8("data_type") {
65            Ok(value) => match value {
66                1 => DataType::Struct,
67                2 => DataType::Str,
68                6 => DataType::U64, // TODO it's a pointer!
69                99 => {
70                    if let Ok(size) = event.get_value_u64("size") {
71                        match size {
72                            1 => DataType::U8,
73                            4 => DataType::U32,
74                            8 => DataType::U64,
75                            _ => return Err("Invalid size of integer type"),
76                        }
77                    } else {
78                        return Err("Cannot read field size");
79                    }
80                }
81                _ => return Err("Invalid data type"),
82            },
83            Err(_) => return Err("Cannot read field data type"),
84        };
85
86        match self.registry.get_klass_by_id_mut(klass_id) {
87            Some(klass) => {
88                klass.add_field(field_name, type_name, data_type);
89                Ok(())
90            }
91            None => Err("Cannot find klass"),
92        }
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99    use crate::event::Value;
100
101    fn make_klass_info_event(
102        id: Option<u32>,
103        name: Option<&str>,
104        field_count: Option<u8>,
105    ) -> Event {
106        let mut values = std::collections::HashMap::new();
107
108        if id.is_some() {
109            values.insert("info_klass_id".to_string(), Value::U32(id.unwrap()));
110        }
111        if name.is_some() {
112            values.insert(
113                "event_klass_name".to_string(),
114                Value::Str(name.unwrap().to_string()),
115            );
116        }
117        if field_count.is_some() {
118            values.insert("field_count".to_string(), Value::U8(field_count.unwrap()));
119        }
120
121        Event::new(CoreEventKlassId::KlassInfo as u32, values)
122    }
123
124    fn make_field_info_event(
125        klass_id: Option<u32>,
126        field_type: Option<&str>,
127        field_name: Option<&str>,
128        size: Option<u64>,
129        data_type: Option<u8>,
130    ) -> Event {
131        let mut values = std::collections::HashMap::new();
132
133        if klass_id.is_some() {
134            values.insert("info_klass_id".to_string(), Value::U32(klass_id.unwrap()));
135        }
136        if field_type.is_some() {
137            values.insert(
138                "field_type".to_string(),
139                Value::Str(field_type.unwrap().to_string()),
140            );
141        }
142        if field_name.is_some() {
143            values.insert(
144                "field_name".to_string(),
145                Value::Str(field_name.unwrap().to_string()),
146            );
147        }
148        if size.is_some() {
149            values.insert("size".to_string(), Value::U64(size.unwrap()));
150        }
151        if data_type.is_some() {
152            values.insert("data_type".to_string(), Value::U8(data_type.unwrap()));
153        }
154
155        Event::new(CoreEventKlassId::FieldInfo as u32, values)
156    }
157
158    #[test]
159    fn should_fail_if_event_is_not_field_or_klass_info_event() {
160        let mut registry = EventKlassRegistry::new();
161        let mut updater = RegistryUpdater::new(&mut registry);
162        let event = Event::new(99, std::collections::HashMap::new());
163
164        assert!(updater.update_registry_from_event(&event).is_err());
165    }
166
167    #[test]
168    fn should_add_new_klass_to_registry_if_all_fields_are_in_event() {
169        let mut registry = EventKlassRegistry::new();
170
171        {
172            let mut updater = RegistryUpdater::new(&mut registry);
173            assert!(updater
174                .update_registry_from_event(&make_klass_info_event(Some(99), Some("name"), Some(0)))
175                .is_ok());
176        }
177
178        assert!(registry.get_klass_by_id(99).is_some());
179        assert!(registry.get_klass_by_name("name").is_some());
180    }
181
182    #[test]
183    fn add_new_klass_to_registry_if_some_fields_are_missing_should_fail() {
184        let mut registry = EventKlassRegistry::new();
185
186        {
187            let mut updater = RegistryUpdater::new(&mut registry);
188            assert!(updater
189                .update_registry_from_event(&make_klass_info_event(None, Some("name"), Some(0)))
190                .is_err());
191            assert!(updater
192                .update_registry_from_event(&make_klass_info_event(Some(99), None, Some(0)))
193                .is_err());
194        }
195    }
196
197    #[test]
198    fn add_core_klass_to_registry_should_not_fail() {
199        let mut registry = EventKlassRegistry::new();
200
201        {
202            let mut updater = RegistryUpdater::new(&mut registry);
203            assert!(updater
204                .update_registry_from_event(&make_klass_info_event(
205                    Some(CoreEventKlassId::Base as u32),
206                    Some("new_name"),
207                    Some(0)
208                ))
209                .is_ok());
210        }
211
212        assert_eq!(
213            *registry
214                .get_klass_by_id(CoreEventKlassId::Base as u32)
215                .unwrap()
216                .get_name(),
217            "HT_Event".to_string()
218        );
219    }
220
221    #[test]
222    fn add_field_to_non_existing_klass_should_fail() {
223        let mut registry = EventKlassRegistry::new();
224
225        {
226            let mut updater = RegistryUpdater::new(&mut registry);
227            let event = make_field_info_event(Some(99), Some("t"), Some("n"), Some(4), Some(99));
228            assert!(updater.update_registry_from_event(&event).is_err());
229        }
230    }
231
232    #[test]
233    fn add_field_if_some_values_are_missing_should_fail() {
234        let mut registry = EventKlassRegistry::new();
235        let mut updater = RegistryUpdater::new(&mut registry);
236        assert!(updater
237            .update_registry_from_event(&make_klass_info_event(Some(99), Some("name"), Some(10)))
238            .is_ok());
239
240        assert!(updater
241            .update_registry_from_event(&make_field_info_event(
242                None,
243                Some("t"),
244                Some("n"),
245                Some(4),
246                Some(1)
247            ))
248            .is_err());
249        assert!(updater
250            .update_registry_from_event(&make_field_info_event(
251                Some(99),
252                None,
253                Some("n"),
254                Some(4),
255                Some(2)
256            ))
257            .is_err());
258        assert!(updater
259            .update_registry_from_event(&make_field_info_event(
260                Some(99),
261                Some("u"),
262                None,
263                Some(4),
264                Some(6)
265            ))
266            .is_err());
267        assert!(updater
268            .update_registry_from_event(&make_field_info_event(
269                Some(99),
270                Some("v"),
271                Some("n"),
272                None,
273                Some(99)
274            ))
275            .is_err());
276        assert!(updater
277            .update_registry_from_event(&make_field_info_event(
278                Some(99),
279                Some("w"),
280                Some("n"),
281                Some(99),
282                None
283            ))
284            .is_err());
285    }
286
287    #[test]
288    fn add_field_to_core_klass_should_not_update_klass() {
289        let mut registry = EventKlassRegistry::new();
290
291        {
292            let mut updater = RegistryUpdater::new(&mut registry);
293            let event = make_field_info_event(
294                Some(CoreEventKlassId::Base as u32),
295                Some("t"),
296                Some("n"),
297                Some(4),
298                Some(99),
299            );
300            assert!(updater.update_registry_from_event(&event).is_ok());
301        }
302
303        assert_eq!(
304            registry
305                .get_klass_by_id(CoreEventKlassId::Base as u32)
306                .unwrap()
307                .get_fields()
308                .len(),
309            3
310        );
311    }
312
313    #[test]
314    fn add_uint_field_with_invalid_size_should_fail() {
315        let mut registry = EventKlassRegistry::new();
316        let mut updater = RegistryUpdater::new(&mut registry);
317        assert!(updater
318            .update_registry_from_event(&make_klass_info_event(Some(99), Some("name"), Some(10)))
319            .is_ok());
320
321        assert!(updater
322            .update_registry_from_event(&make_field_info_event(
323                Some(99),
324                Some("t"),
325                Some("n"),
326                Some(99),
327                Some(10)
328            ))
329            .is_err());
330    }
331}