Skip to main content

dampen_cli/commands/check/
handlers.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashSet;
3use std::fs;
4use std::path::Path;
5
6/// Definition of a handler function.
7#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8pub struct HandlerDefinition {
9    /// Handler function name as referenced in XML `on_*` attributes
10    pub name: String,
11
12    /// Expected message type; null for unit/no params
13    #[serde(default)]
14    pub param_type: Option<String>,
15
16    /// Whether handler returns Command for async operations
17    #[serde(default)]
18    pub returns_command: bool,
19}
20
21/// Registry of event handlers for validation.
22#[derive(Debug, Clone, Default)]
23pub struct HandlerRegistry {
24    handlers: HashSet<HandlerDefinition>,
25}
26
27impl HandlerRegistry {
28    /// Creates a new empty registry.
29    pub fn new() -> Self {
30        Self {
31            handlers: HashSet::new(),
32        }
33    }
34
35    /// Loads a handler registry from a JSON file.
36    ///
37    /// # Arguments
38    ///
39    /// * `path` - Path to the JSON file containing handler definitions
40    ///
41    /// # Returns
42    ///
43    /// A `Result` containing the registry or an error if loading fails.
44    ///
45    /// # Example JSON format
46    ///
47    /// ```json
48    /// [
49    ///   {
50    ///     "name": "increment",
51    ///     "param_type": null,
52    ///     "returns_command": false
53    ///   },
54    ///   {
55    ///     "name": "setValue",
56    ///     "param_type": "i32",
57    ///     "returns_command": true
58    ///   }
59    /// ]
60    /// ```
61    pub fn load_from_json(path: &Path) -> Result<Self, Box<dyn std::error::Error>> {
62        let content = fs::read_to_string(path)?;
63        let handlers: Vec<HandlerDefinition> = serde_json::from_str(&content)?;
64
65        let mut registry = Self::new();
66        for handler in handlers {
67            registry.add_handler(handler);
68        }
69
70        Ok(registry)
71    }
72
73    /// Checks if a handler is registered.
74    ///
75    /// # Arguments
76    ///
77    /// * `name` - Handler name to check
78    ///
79    /// # Returns
80    ///
81    /// `true` if the handler is registered, `false` otherwise.
82    pub fn contains(&self, name: &str) -> bool {
83        self.handlers.iter().any(|h| h.name == name)
84    }
85
86    /// Gets all handler names.
87    ///
88    /// # Returns
89    ///
90    /// A vector of all registered handler names.
91    pub fn all_names(&self) -> Vec<String> {
92        self.handlers.iter().map(|h| h.name.clone()).collect()
93    }
94
95    /// Adds a handler to the registry.
96    pub fn add_handler(&mut self, handler: HandlerDefinition) {
97        self.handlers.insert(handler);
98    }
99
100    /// Gets the number of registered handlers.
101    pub fn len(&self) -> usize {
102        self.handlers.len()
103    }
104
105    /// Checks if the registry is empty.
106    pub fn is_empty(&self) -> bool {
107        self.handlers.is_empty()
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn test_empty_registry() {
117        let registry = HandlerRegistry::new();
118        assert!(registry.is_empty());
119        assert_eq!(registry.len(), 0);
120        assert!(!registry.contains("increment"));
121    }
122
123    #[test]
124    fn test_add_handler() {
125        let mut registry = HandlerRegistry::new();
126
127        let handler = HandlerDefinition {
128            name: "increment".to_string(),
129            param_type: None,
130            returns_command: false,
131        };
132
133        registry.add_handler(handler);
134
135        assert!(!registry.is_empty());
136        assert_eq!(registry.len(), 1);
137        assert!(registry.contains("increment"));
138        assert!(!registry.contains("decrement"));
139    }
140
141    #[test]
142    fn test_all_names() {
143        let mut registry = HandlerRegistry::new();
144
145        registry.add_handler(HandlerDefinition {
146            name: "increment".to_string(),
147            param_type: None,
148            returns_command: false,
149        });
150
151        registry.add_handler(HandlerDefinition {
152            name: "decrement".to_string(),
153            param_type: None,
154            returns_command: false,
155        });
156
157        let names = registry.all_names();
158        assert_eq!(names.len(), 2);
159        assert!(names.contains(&"increment".to_string()));
160        assert!(names.contains(&"decrement".to_string()));
161    }
162
163    #[test]
164    fn test_duplicate_handlers() {
165        let mut registry = HandlerRegistry::new();
166
167        let handler = HandlerDefinition {
168            name: "increment".to_string(),
169            param_type: None,
170            returns_command: false,
171        };
172
173        registry.add_handler(handler.clone());
174        registry.add_handler(handler.clone());
175
176        // HashSet should prevent duplicates
177        assert_eq!(registry.len(), 1);
178    }
179}