elif_core/modules/
registry.rs

1use crate::container::ContainerBuilder;
2use crate::modules::{Module, ModuleError, ModuleMetadata, RouteDefinition, MiddlewareDefinition};
3use std::collections::HashMap;
4
5/// Module registry for managing module lifecycle and dependencies
6pub struct ModuleRegistry {
7    modules: Vec<Box<dyn Module>>,
8    loading_order: Vec<usize>,
9    routes: Vec<RouteDefinition>,
10    middleware: Vec<MiddlewareDefinition>,
11    metadata_cache: HashMap<String, ModuleMetadata>,
12}
13
14impl ModuleRegistry {
15    /// Create a new module registry
16    pub fn new() -> Self {
17        Self {
18            modules: Vec::new(),
19            loading_order: Vec::new(),
20            routes: Vec::new(),
21            middleware: Vec::new(),
22            metadata_cache: HashMap::new(),
23        }
24    }
25    
26    /// Register a module
27    pub fn register<M: Module + 'static>(&mut self, module: M) {
28        let metadata = ModuleMetadata::from_module(&module);
29        let name = metadata.name.clone();
30        
31        self.modules.push(Box::new(module));
32        self.metadata_cache.insert(name, metadata);
33    }
34    
35    /// Get the number of registered modules
36    pub fn module_count(&self) -> usize {
37        self.modules.len()
38    }
39    
40    /// Get module metadata by name
41    pub fn get_metadata(&self, name: &str) -> Option<&ModuleMetadata> {
42        self.metadata_cache.get(name)
43    }
44    
45    /// Get all module metadata
46    pub fn all_metadata(&self) -> Vec<&ModuleMetadata> {
47        self.metadata_cache.values().collect()
48    }
49    
50    /// Check if a module is registered
51    pub fn has_module(&self, name: &str) -> bool {
52        self.modules.iter().any(|m| m.name() == name)
53    }
54    
55    /// Resolve module dependencies and determine loading order
56    pub fn resolve_dependencies(&mut self) -> Result<(), ModuleError> {
57        let module_count = self.modules.len();
58        
59        // Create name to index mapping
60        let name_to_index: HashMap<String, usize> = self.modules
61            .iter()
62            .enumerate()
63            .map(|(i, m)| (m.name().to_string(), i))
64            .collect();
65        
66        // Perform topological sort
67        let mut visited = vec![false; module_count];
68        let mut temp_mark = vec![false; module_count];
69        let mut result = Vec::new();
70        
71        for i in 0..module_count {
72            if !visited[i] {
73                self.visit_module(i, &name_to_index, &mut visited, &mut temp_mark, &mut result)?;
74            }
75        }
76        
77        self.loading_order = result;
78        Ok(())
79    }
80    
81    /// Visit module for dependency resolution (topological sort)
82    fn visit_module(
83        &self,
84        index: usize,
85        name_to_index: &HashMap<String, usize>,
86        visited: &mut Vec<bool>,
87        temp_mark: &mut Vec<bool>,
88        result: &mut Vec<usize>,
89    ) -> Result<(), ModuleError> {
90        if temp_mark[index] {
91            return Err(ModuleError::CircularDependency {
92                module: self.modules[index].name().to_string(),
93            });
94        }
95        
96        if visited[index] {
97            return Ok(());
98        }
99        
100        temp_mark[index] = true;
101        
102        // Visit all dependencies first
103        let dependencies = self.modules[index].dependencies();
104        for dep_name in dependencies {
105            if let Some(&dep_index) = name_to_index.get(dep_name) {
106                self.visit_module(dep_index, name_to_index, visited, temp_mark, result)?;
107            } else {
108                return Err(ModuleError::MissingDependency {
109                    module: self.modules[index].name().to_string(),
110                    dependency: dep_name.to_string(),
111                });
112            }
113        }
114        
115        temp_mark[index] = false;
116        visited[index] = true;
117        result.push(index);
118        
119        Ok(())
120    }
121    
122    /// Configure all modules with the container builder
123    pub fn configure_all(&self, mut builder: ContainerBuilder) -> Result<ContainerBuilder, ModuleError> {
124        for &index in &self.loading_order {
125            let module = &self.modules[index];
126            tracing::info!("Configuring module: {}", module.name());
127            builder = module.configure(builder)?;
128        }
129        Ok(builder)
130    }
131    
132    /// Boot all modules after container is built
133    pub fn boot_all(&self, container: &crate::container::Container) -> Result<(), ModuleError> {
134        for &index in &self.loading_order {
135            let module = &self.modules[index];
136            tracing::info!("Booting module: {}", module.name());
137            module.boot(container).map_err(|e| {
138                ModuleError::BootFailed {
139                    message: format!("Failed to boot module '{}': {}", module.name(), e),
140                }
141            })?;
142        }
143        Ok(())
144    }
145    
146    /// Collect all routes from registered modules
147    pub fn collect_routes(&mut self) -> Vec<RouteDefinition> {
148        if self.routes.is_empty() {
149            for module in &self.modules {
150                self.routes.extend(module.routes());
151            }
152        }
153        self.routes.clone()
154    }
155    
156    /// Collect all middleware from registered modules
157    pub fn collect_middleware(&mut self) -> Vec<MiddlewareDefinition> {
158        if self.middleware.is_empty() {
159            for module in &self.modules {
160                self.middleware.extend(module.middleware());
161            }
162            // Sort middleware by priority
163            self.middleware.sort();
164        }
165        self.middleware.clone()
166    }
167    
168    /// Get modules in loading order
169    pub fn modules_in_order(&self) -> Vec<&dyn Module> {
170        self.loading_order
171            .iter()
172            .map(|&index| self.modules[index].as_ref())
173            .collect()
174    }
175    
176    /// Validate all modules
177    pub fn validate(&self) -> Result<(), ModuleError> {
178        // Check for duplicate module names
179        let mut names = std::collections::HashSet::new();
180        for module in &self.modules {
181            let name = module.name();
182            if names.contains(name) {
183                return Err(ModuleError::ConfigurationFailed {
184                    message: format!("Duplicate module name: {}", name),
185                });
186            }
187            names.insert(name);
188        }
189        
190        // Check dependencies exist
191        for module in &self.modules {
192            for dep in module.dependencies() {
193                if !names.contains(dep) {
194                    return Err(ModuleError::MissingDependency {
195                        module: module.name().to_string(),
196                        dependency: dep.to_string(),
197                    });
198                }
199            }
200        }
201        
202        Ok(())
203    }
204    
205    /// Clear all modules (useful for testing)
206    pub fn clear(&mut self) {
207        self.modules.clear();
208        self.loading_order.clear();
209        self.routes.clear();
210        self.middleware.clear();
211        self.metadata_cache.clear();
212    }
213}
214
215impl Default for ModuleRegistry {
216    fn default() -> Self {
217        Self::new()
218    }
219}
220
221impl std::fmt::Debug for ModuleRegistry {
222    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223        f.debug_struct("ModuleRegistry")
224            .field("module_count", &self.modules.len())
225            .field("route_count", &self.routes.len())
226            .field("middleware_count", &self.middleware.len())
227            .field("loading_order", &self.loading_order)
228            .finish()
229    }
230}
231
232#[cfg(test)]
233mod tests {
234    use super::*;
235    use crate::modules::{BaseModule, Module};
236    
237    #[tokio::test]
238    async fn test_module_registry() -> Result<(), ModuleError> {
239        let mut registry = ModuleRegistry::new();
240        
241        // Register modules with dependencies
242        let module_a = BaseModule::new("module_a");
243        let module_b = BaseModule::new("module_b").with_dependencies(vec!["module_a"]);
244        let module_c = BaseModule::new("module_c").with_dependencies(vec!["module_b", "module_a"]);
245        
246        registry.register(module_a);
247        registry.register(module_b);
248        registry.register(module_c);
249        
250        assert_eq!(registry.module_count(), 3);
251        
252        // Resolve dependencies
253        registry.resolve_dependencies()?;
254        
255        // Check loading order
256        let modules_in_order = registry.modules_in_order();
257        let names: Vec<&str> = modules_in_order.iter().map(|m| m.name()).collect();
258        
259        // module_a should be first, module_c should be last
260        assert_eq!(names[0], "module_a");
261        assert_eq!(names[2], "module_c");
262        
263        Ok(())
264    }
265    
266    #[tokio::test]
267    async fn test_circular_dependency_detection() {
268        let mut registry = ModuleRegistry::new();
269        
270        let module_a = BaseModule::new("module_a").with_dependencies(vec!["module_b"]);
271        let module_b = BaseModule::new("module_b").with_dependencies(vec!["module_a"]);
272        
273        registry.register(module_a);
274        registry.register(module_b);
275        
276        let result = registry.resolve_dependencies();
277        assert!(result.is_err());
278        
279        if let Err(ModuleError::CircularDependency { module }) = result {
280            assert!(module == "module_a" || module == "module_b");
281        } else {
282            panic!("Expected circular dependency error");
283        }
284    }
285}