Skip to main content

rsigma_eval/event/
map.rs

1use std::borrow::Cow;
2use std::collections::HashMap;
3
4use serde_json::Value;
5
6use super::{Event, EventValue};
7
8/// Generic flat-map event for user-defined key-value stores.
9///
10/// Flat key lookup only (no dot-notation, no nesting).
11#[derive(Debug, Clone)]
12pub struct MapEvent<K = String, V = String>
13where
14    K: AsRef<str> + std::fmt::Debug + Clone,
15    V: AsRef<str> + std::fmt::Debug + Clone,
16{
17    inner: HashMap<K, V>,
18}
19
20impl<K, V> MapEvent<K, V>
21where
22    K: AsRef<str> + std::fmt::Debug + Clone,
23    V: AsRef<str> + std::fmt::Debug + Clone,
24{
25    pub fn new(inner: HashMap<K, V>) -> Self {
26        Self { inner }
27    }
28}
29
30impl<K, V> Event for MapEvent<K, V>
31where
32    K: AsRef<str> + std::fmt::Debug + Clone,
33    V: AsRef<str> + std::fmt::Debug + Clone,
34{
35    fn get_field(&self, path: &str) -> Option<EventValue<'_>> {
36        self.inner
37            .iter()
38            .find(|(k, _)| k.as_ref() == path)
39            .map(|(_, v)| EventValue::Str(Cow::Borrowed(v.as_ref())))
40    }
41
42    fn any_string_value(&self, pred: &dyn Fn(&str) -> bool) -> bool {
43        self.inner.values().any(|v| pred(v.as_ref()))
44    }
45
46    fn all_string_values(&self) -> Vec<Cow<'_, str>> {
47        self.inner
48            .values()
49            .map(|v| Cow::Borrowed(v.as_ref()))
50            .collect()
51    }
52
53    fn to_json(&self) -> Value {
54        let map: serde_json::Map<String, Value> = self
55            .inner
56            .iter()
57            .map(|(k, v)| {
58                (
59                    k.as_ref().to_string(),
60                    Value::String(v.as_ref().to_string()),
61                )
62            })
63            .collect();
64        Value::Object(map)
65    }
66
67    fn field_keys(&self) -> Vec<Cow<'_, str>> {
68        self.inner
69            .keys()
70            .map(|k| Cow::Borrowed(k.as_ref()))
71            .collect()
72    }
73
74    fn top_level_keys(&self) -> Option<Vec<Cow<'_, str>>> {
75        Some(
76            self.inner
77                .keys()
78                .map(|k| Cow::Borrowed(k.as_ref()))
79                .collect(),
80        )
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use serde_json::json;
88
89    #[test]
90    fn map_event_get_field() {
91        let mut m = HashMap::new();
92        m.insert("user".to_string(), "admin".to_string());
93        let event = MapEvent::new(m);
94        assert_eq!(
95            event.get_field("user"),
96            Some(EventValue::Str(Cow::Borrowed("admin")))
97        );
98        assert_eq!(event.get_field("missing"), None);
99    }
100
101    #[test]
102    fn map_event_to_json() {
103        let mut m = HashMap::new();
104        m.insert("k".to_string(), "v".to_string());
105        let event = MapEvent::new(m);
106        assert_eq!(event.to_json(), json!({"k": "v"}));
107    }
108
109    #[test]
110    fn map_event_field_keys() {
111        let mut m = HashMap::new();
112        m.insert("user".to_string(), "admin".to_string());
113        m.insert("host".to_string(), "web01".to_string());
114        let event = MapEvent::new(m);
115        let mut keys: Vec<String> = event.field_keys().iter().map(|c| c.to_string()).collect();
116        keys.sort();
117        assert_eq!(keys, vec!["host", "user"]);
118    }
119}