Skip to main content

rydit_core/
lib.rs

1//! RyDit Core - Trait y Registro para módulos
2//! 
3//! Proporciona la interfaz común que todos los módulos deben implementar.
4
5use std::collections::HashMap;
6use serde_json::Value;
7
8/// Resultado de operación de módulo
9pub type ModuleResult = Result<Value, ModuleError>;
10
11/// Error de módulo
12#[derive(Debug, Clone)]
13pub struct ModuleError {
14    pub code: String,
15    pub message: String,
16}
17
18impl std::fmt::Display for ModuleError {
19    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
20        write!(f, "[{}] {}", self.code, self.message)
21    }
22}
23
24impl std::error::Error for ModuleError {}
25
26/// Trait que todos los módulos deben implementar
27pub trait RyditModule: Send + Sync {
28    /// Nombre único del módulo
29    fn name(&self) -> &'static str;
30    
31    /// Versión del módulo
32    fn version(&self) -> &'static str;
33    
34    /// Registro de comandos disponibles
35    /// Retorna: HashMap<nombre_comando, descripción>
36    fn register(&self) -> HashMap<&'static str, &'static str>;
37    
38    /// Ejecuta un comando con parámetros
39    /// 
40    /// # Arguments
41    /// * `command` - Nombre del comando
42    /// * `params` - Parámetros JSON
43    fn execute(&self, command: &str, params: Value) -> ModuleResult;
44}
45
46/// Registro de módulos disponibles
47#[derive(Default)]
48pub struct ModuleRegistry {
49    modules: HashMap<String, Box<dyn RyditModule>>,
50}
51
52impl ModuleRegistry {
53    /// Crea un nuevo registro vacío
54    pub fn new() -> Self {
55        Self {
56            modules: HashMap::new(),
57        }
58    }
59    
60    /// Registra un módulo
61    pub fn register<M: RyditModule + 'static>(&mut self, module: M) {
62        let name = module.name().to_string();
63        self.modules.insert(name, Box::new(module));
64    }
65    
66    /// Obtiene un módulo por nombre
67    pub fn get(&self, name: &str) -> Option<&dyn RyditModule> {
68        self.modules.get(name).map(|b| b.as_ref())
69    }
70    
71    /// Lista todos los módulos registrados
72    pub fn list(&self) -> Vec<&str> {
73        self.modules.keys().map(|s| s.as_str()).collect()
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    // Módulo de prueba para tests
82    struct TestModule;
83
84    impl RyditModule for TestModule {
85        fn name(&self) -> &'static str {
86            "test"
87        }
88
89        fn version(&self) -> &'static str {
90            "1.0.0"
91        }
92
93        fn register(&self) -> HashMap<&'static str, &'static str> {
94            let mut cmds = HashMap::new();
95            cmds.insert("ping", "Test ping command");
96            cmds.insert("echo", "Test echo command");
97            cmds
98        }
99
100        fn execute(&self, command: &str, params: Value) -> ModuleResult {
101            match command {
102                "ping" => Ok(Value::String("pong".to_string())),
103                "echo" => Ok(params),
104                _ => Err(ModuleError {
105                    code: "UNKNOWN_COMMAND".to_string(),
106                    message: format!("Unknown command: {}", command),
107                }),
108            }
109        }
110    }
111
112    #[test]
113    fn test_module_registry() {
114        let mut registry = ModuleRegistry::new();
115        registry.register(TestModule);
116        
117        assert_eq!(registry.list().len(), 1);
118        assert!(registry.get("test").is_some());
119        assert!(registry.get("unknown").is_none());
120    }
121
122    #[test]
123    fn test_module_execute_ping() {
124        let mut registry = ModuleRegistry::new();
125        registry.register(TestModule);
126        
127        let module = registry.get("test").unwrap();
128        let result = module.execute("ping", Value::Null).unwrap();
129        assert_eq!(result, Value::String("pong".to_string()));
130    }
131
132    #[test]
133    fn test_module_execute_echo() {
134        let mut registry = ModuleRegistry::new();
135        registry.register(TestModule);
136        
137        let module = registry.get("test").unwrap();
138        let input = Value::String("hello".to_string());
139        let result = module.execute("echo", input.clone()).unwrap();
140        assert_eq!(result, input);
141    }
142
143    #[test]
144    fn test_module_error() {
145        let mut registry = ModuleRegistry::new();
146        registry.register(TestModule);
147        
148        let module = registry.get("test").unwrap();
149        let result = module.execute("unknown", Value::Null);
150        assert!(result.is_err());
151        
152        let err = result.unwrap_err();
153        assert_eq!(err.code, "UNKNOWN_COMMAND");
154    }
155}