elif_core/modules/
registry.rs1use crate::container::ContainerBuilder;
2use crate::modules::{MiddlewareDefinition, Module, ModuleError, ModuleMetadata, RouteDefinition};
3use std::collections::HashMap;
4
5pub 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 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 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 pub fn module_count(&self) -> usize {
37 self.modules.len()
38 }
39
40 pub fn get_metadata(&self, name: &str) -> Option<&ModuleMetadata> {
42 self.metadata_cache.get(name)
43 }
44
45 pub fn all_metadata(&self) -> Vec<&ModuleMetadata> {
47 self.metadata_cache.values().collect()
48 }
49
50 pub fn has_module(&self, name: &str) -> bool {
52 self.modules.iter().any(|m| m.name() == name)
53 }
54
55 pub fn resolve_dependencies(&mut self) -> Result<(), ModuleError> {
57 let module_count = self.modules.len();
58
59 let name_to_index: HashMap<String, usize> = self
61 .modules
62 .iter()
63 .enumerate()
64 .map(|(i, m)| (m.name().to_string(), i))
65 .collect();
66
67 let mut visited = vec![false; module_count];
69 let mut temp_mark = vec![false; module_count];
70 let mut result = Vec::new();
71
72 for i in 0..module_count {
73 if !visited[i] {
74 self.visit_module(i, &name_to_index, &mut visited, &mut temp_mark, &mut result)?;
75 }
76 }
77
78 self.loading_order = result;
79 Ok(())
80 }
81
82 fn visit_module(
84 &self,
85 index: usize,
86 name_to_index: &HashMap<String, usize>,
87 visited: &mut Vec<bool>,
88 temp_mark: &mut Vec<bool>,
89 result: &mut Vec<usize>,
90 ) -> Result<(), ModuleError> {
91 if temp_mark[index] {
92 return Err(ModuleError::CircularDependency {
93 module: self.modules[index].name().to_string(),
94 });
95 }
96
97 if visited[index] {
98 return Ok(());
99 }
100
101 temp_mark[index] = true;
102
103 let dependencies = self.modules[index].dependencies();
105 for dep_name in dependencies {
106 if let Some(&dep_index) = name_to_index.get(dep_name) {
107 self.visit_module(dep_index, name_to_index, visited, temp_mark, result)?;
108 } else {
109 return Err(ModuleError::MissingDependency {
110 module: self.modules[index].name().to_string(),
111 dependency: dep_name.to_string(),
112 });
113 }
114 }
115
116 temp_mark[index] = false;
117 visited[index] = true;
118 result.push(index);
119
120 Ok(())
121 }
122
123 pub fn configure_all(
125 &self,
126 mut builder: ContainerBuilder,
127 ) -> Result<ContainerBuilder, ModuleError> {
128 for &index in &self.loading_order {
129 let module = &self.modules[index];
130 tracing::info!("Configuring module: {}", module.name());
131 builder = module.configure(builder)?;
132 }
133 Ok(builder)
134 }
135
136 pub fn boot_all(&self, container: &crate::container::Container) -> Result<(), ModuleError> {
138 for &index in &self.loading_order {
139 let module = &self.modules[index];
140 tracing::info!("Booting module: {}", module.name());
141 module
142 .boot(container)
143 .map_err(|e| ModuleError::BootFailed {
144 message: format!("Failed to boot module '{}': {}", module.name(), e),
145 })?;
146 }
147 Ok(())
148 }
149
150 pub fn collect_routes(&mut self) -> Vec<RouteDefinition> {
152 if self.routes.is_empty() {
153 for module in &self.modules {
154 self.routes.extend(module.routes());
155 }
156 }
157 self.routes.clone()
158 }
159
160 pub fn collect_middleware(&mut self) -> Vec<MiddlewareDefinition> {
162 if self.middleware.is_empty() {
163 for module in &self.modules {
164 self.middleware.extend(module.middleware());
165 }
166 self.middleware.sort();
168 }
169 self.middleware.clone()
170 }
171
172 pub fn modules_in_order(&self) -> Vec<&dyn Module> {
174 self.loading_order
175 .iter()
176 .map(|&index| self.modules[index].as_ref())
177 .collect()
178 }
179
180 pub fn validate(&self) -> Result<(), ModuleError> {
182 let mut names = std::collections::HashSet::new();
184 for module in &self.modules {
185 let name = module.name();
186 if names.contains(name) {
187 return Err(ModuleError::ConfigurationFailed {
188 message: format!("Duplicate module name: {}", name),
189 });
190 }
191 names.insert(name);
192 }
193
194 for module in &self.modules {
196 for dep in module.dependencies() {
197 if !names.contains(dep) {
198 return Err(ModuleError::MissingDependency {
199 module: module.name().to_string(),
200 dependency: dep.to_string(),
201 });
202 }
203 }
204 }
205
206 Ok(())
207 }
208
209 pub fn clear(&mut self) {
211 self.modules.clear();
212 self.loading_order.clear();
213 self.routes.clear();
214 self.middleware.clear();
215 self.metadata_cache.clear();
216 }
217}
218
219impl Default for ModuleRegistry {
220 fn default() -> Self {
221 Self::new()
222 }
223}
224
225impl std::fmt::Debug for ModuleRegistry {
226 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227 f.debug_struct("ModuleRegistry")
228 .field("module_count", &self.modules.len())
229 .field("route_count", &self.routes.len())
230 .field("middleware_count", &self.middleware.len())
231 .field("loading_order", &self.loading_order)
232 .finish()
233 }
234}
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239 use crate::modules::BaseModule;
240
241 #[tokio::test]
242 async fn test_module_registry() -> Result<(), ModuleError> {
243 let mut registry = ModuleRegistry::new();
244
245 let module_a = BaseModule::new("module_a");
247 let module_b = BaseModule::new("module_b").with_dependencies(vec!["module_a"]);
248 let module_c = BaseModule::new("module_c").with_dependencies(vec!["module_b", "module_a"]);
249
250 registry.register(module_a);
251 registry.register(module_b);
252 registry.register(module_c);
253
254 assert_eq!(registry.module_count(), 3);
255
256 registry.resolve_dependencies()?;
258
259 let modules_in_order = registry.modules_in_order();
261 let names: Vec<&str> = modules_in_order.iter().map(|m| m.name()).collect();
262
263 assert_eq!(names[0], "module_a");
265 assert_eq!(names[2], "module_c");
266
267 Ok(())
268 }
269
270 #[tokio::test]
271 async fn test_circular_dependency_detection() {
272 let mut registry = ModuleRegistry::new();
273
274 let module_a = BaseModule::new("module_a").with_dependencies(vec!["module_b"]);
275 let module_b = BaseModule::new("module_b").with_dependencies(vec!["module_a"]);
276
277 registry.register(module_a);
278 registry.register(module_b);
279
280 let result = registry.resolve_dependencies();
281 assert!(result.is_err());
282
283 if let Err(ModuleError::CircularDependency { module }) = result {
284 assert!(module == "module_a" || module == "module_b");
285 } else {
286 panic!("Expected circular dependency error");
287 }
288 }
289}