hawktracer_parser/
event.rs

1#[derive(Copy, Clone, PartialEq, Debug)]
2pub enum DataType {
3    U8,
4    I8,
5    U16,
6    I16,
7    U32,
8    I32,
9    U64,
10    I64,
11    Str,
12    Struct,
13}
14
15#[derive(Debug, PartialEq, Clone)]
16pub enum ErrorKind {
17    NotFound,
18    InvalidType,
19}
20
21#[derive(Debug, PartialEq)]
22pub struct Event {
23    klass_id: u32,
24    values: std::collections::HashMap<String, Value>,
25}
26
27#[derive(Debug)]
28pub struct ValueError {
29    kind: ErrorKind,
30    field: String,
31}
32
33impl ValueError {
34    pub fn new(field: &str, kind: ErrorKind) -> ValueError {
35        ValueError {
36            kind,
37            field: field.to_string(),
38        }
39    }
40
41    pub fn kind(&self) -> ErrorKind {
42        self.kind.clone()
43    }
44}
45
46impl std::error::Error for ValueError {}
47
48impl std::fmt::Display for ValueError {
49    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
50        write!(f, "Cannot get value {}: {:?}>", self.field, self.kind)
51    }
52}
53
54// Keep in sync with DataType
55// TODO: can we merge those two enums?
56#[derive(Debug, PartialEq)]
57pub enum Value {
58    U8(u8),
59    I8(i8),
60    U16(u16),
61    I16(i16),
62    U32(u32),
63    I32(i32),
64    U64(u64),
65    I64(i64),
66    Str(String),
67    Struct(Event),
68}
69
70impl std::fmt::Display for Value {
71    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
72        match self {
73            Value::U8(v) => write!(f, "{}", v),
74            Value::I8(v) => write!(f, "{}", v),
75            Value::U16(v) => write!(f, "{}", v),
76            Value::I16(v) => write!(f, "{}", v),
77            Value::U32(v) => write!(f, "{}", v),
78            Value::I32(v) => write!(f, "{}", v),
79            Value::U64(v) => write!(f, "{}", v),
80            Value::I64(v) => write!(f, "{}", v),
81            Value::Str(v) => write!(f, "\"{}\"", v),
82            Value::Struct(v) => write!(f, "<Event {}>", v.get_klass_id()),
83        }
84    }
85}
86
87macro_rules! make_field_getter {
88    ($function_name: ident, $data_type: ident, $type: ty) => (
89        pub fn $function_name(&self, name: &str) -> Result<$type, ValueError> {
90            match self.values.get(name) {
91                Some(value) => {
92                    if let Value::$data_type(data) = value {
93                        Ok(*data)
94                    } else {
95                        Err(ValueError::new(name, ErrorKind::InvalidType))
96                    }
97                },
98                None => Err(ValueError::new(name, ErrorKind::NotFound))
99            }
100        }
101    )
102}
103
104macro_rules! make_field_getter_ref {
105    ($function_name: ident, $data_type: ident, $type: ty) => (
106        pub fn $function_name(&self, name: &str) -> Result<$type, ValueError> {
107            match self.values.get(name) {
108                Some(value) => {
109                    if let Value::$data_type(data) = value {
110                        Ok(data)
111                    } else {
112                        Err(ValueError::new(name, ErrorKind::InvalidType))
113                    }
114                },
115                None => Err(ValueError::new(name, ErrorKind::NotFound))
116            }
117        }
118    )
119}
120
121impl Event {
122    pub fn new(klass_id: u32, values: std::collections::HashMap<String, Value>) -> Event {
123        Event { klass_id, values }
124    }
125
126    make_field_getter!(get_value_u8, U8, u8);
127    make_field_getter!(get_value_i8, I8, i8);
128    make_field_getter!(get_value_u16, U16, u16);
129    make_field_getter!(get_value_i16, I16, i16);
130    make_field_getter!(get_value_u32, U32, u32);
131    make_field_getter!(get_value_i32, I32, i32);
132    make_field_getter!(get_value_u64, U64, u64);
133    make_field_getter!(get_value_i64, I64, i64);
134    make_field_getter_ref!(get_value_string, Str, &String);
135    make_field_getter_ref!(get_value_struct, Struct, &Event);
136
137    pub fn get_raw_value(&self, name: &str) -> Option<&Value> {
138        self.values.get(name)
139    }
140
141    pub fn get_all_values(&self) -> &std::collections::HashMap<String, Value> {
142        &self.values
143    }
144
145    pub fn get_klass_id(&self) -> u32 {
146        self.klass_id
147    }
148
149    pub fn flat_event(self) -> Event {
150        let mut new_values = std::collections::HashMap::<String, Value>::new();
151        let klass_id = self.get_klass_id();
152        self.flat_event_internal(&mut new_values);
153
154        Event::new(klass_id, new_values)
155    }
156
157    fn flat_event_internal(mut self, new_values: &mut std::collections::HashMap<String, Value>) {
158        let base_value = self.values.remove("base");
159
160        for (name, value) in self.values {
161            new_values.insert(name, value);
162        }
163
164        if let Some(base_value) = base_value {
165            if let Value::Struct(event) = base_value {
166                event.flat_event_internal(new_values);
167            } else {
168                new_values.insert("base".to_string(), base_value);
169            }
170        }
171    }
172}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177    use std::collections::HashMap;
178
179    #[test]
180    fn getting_klass_id_should_return_correct_value() {
181        let klass_id = 5;
182        let event = Event::new(klass_id, HashMap::<String, Value>::new());
183        assert_eq!(klass_id, event.get_klass_id());
184    }
185
186    #[test]
187    fn getting_valid_type_should_not_fail() {
188        let u32_value = 492;
189        let mut values = HashMap::<String, Value>::new();
190        values.insert("v1".to_string(), Value::U32(u32_value));
191        let event = Event::new(1, values);
192
193        assert_eq!(
194            event.get_value_u32("v1").expect("value v1 doesn't exist"),
195            u32_value
196        );
197    }
198
199    #[test]
200    fn getting_non_existing_value_should_fail() {
201        let event = Event::new(1, HashMap::<String, Value>::new());
202
203        assert_eq!(
204            event.get_value_u32("non-existing").unwrap_err().kind(),
205            ErrorKind::NotFound
206        );
207    }
208
209    #[test]
210    fn getting_non_existing_string_value_should_fail() {
211        let event = Event::new(1, HashMap::<String, Value>::new());
212
213        assert_eq!(
214            event.get_value_string("non-existing").unwrap_err().kind(),
215            ErrorKind::NotFound
216        );
217    }
218
219    #[test]
220    fn getting_invalid_type_should_fail() {
221        let mut values = HashMap::<String, Value>::new();
222        values.insert("v1".to_string(), Value::U32(2));
223        let event = Event::new(1, values);
224
225        assert_eq!(
226            event.get_value_string("v1").unwrap_err().kind(),
227            ErrorKind::InvalidType
228        );
229    }
230
231    #[test]
232    fn getting_invalid_integer_type_should_fail() {
233        let mut values = HashMap::<String, Value>::new();
234        values.insert("v1".to_string(), Value::U8(2));
235        let event = Event::new(1, values);
236
237        assert_eq!(
238            event.get_value_u32("v1").unwrap_err().kind(),
239            ErrorKind::InvalidType
240        );
241    }
242
243    #[test]
244    fn flatten_event_should_collapse_all_base_struct_events() {
245        let mut super_base_values = HashMap::<String, Value>::new();
246        super_base_values.insert("timestamp".to_string(), Value::U64(999));
247        super_base_values.insert("xxx".to_string(), Value::U64(876));
248
249        let mut base_values = HashMap::<String, Value>::new();
250        base_values.insert(
251            "base".to_string(),
252            Value::Struct(Event::new(1, super_base_values)),
253        );
254        base_values.insert("timestamp".to_string(), Value::U64(123));
255        base_values.insert("id".to_string(), Value::U64(456));
256
257        let mut values = HashMap::<String, Value>::new();
258        values.insert(
259            "base".to_string(),
260            Value::Struct(Event::new(1, base_values)),
261        );
262        values.insert("name".to_string(), Value::Str("some_name".to_string()));
263        let event = Event::new(3, values);
264
265        let event = event.flat_event();
266
267        assert_eq!(4, event.values.len());
268        assert_eq!(3, event.get_klass_id());
269        assert_eq!(event.get_value_u64("timestamp").unwrap(), 999);
270        assert_eq!(event.get_value_u64("id").unwrap(), 456);
271        assert_eq!(event.get_value_u64("xxx").unwrap(), 876);
272        assert_eq!(event.get_value_string("name").unwrap(), "some_name");
273    }
274
275    #[test]
276    fn flatten_event_should_not_collapse_non_event_fields() {
277        let mut values = HashMap::<String, Value>::new();
278        values.insert("base".to_string(), Value::U64(2));
279        values.insert("name".to_string(), Value::Str("some_name".to_string()));
280        let event = Event::new(3, values);
281
282        let event = event.flat_event();
283
284        assert_eq!(2, event.values.len());
285        assert_eq!(event.get_value_u64("base").unwrap(), 2);
286        assert_eq!(event.get_value_string("name").unwrap(), "some_name");
287    }
288}