elif_http/bootstrap/
controller_registry.rs1use std::collections::HashMap;
32use std::sync::RwLock;
33use once_cell::sync::Lazy;
34use crate::controller::ElifController;
35use crate::bootstrap::BootstrapError;
36
37pub type ControllerFactory = fn() -> Box<dyn ElifController>;
39
40#[derive(Debug)]
42pub struct ControllerTypeRegistry {
43 factories: RwLock<HashMap<String, ControllerFactory>>,
45}
46
47impl ControllerTypeRegistry {
48 fn new() -> Self {
50 Self {
51 factories: RwLock::new(HashMap::new()),
52 }
53 }
54
55 pub fn register(&self, name: &str, factory: ControllerFactory) {
67 let mut factories = self.factories.write()
68 .expect("Controller type registry lock poisoned");
69
70 if factories.contains_key(name) {
71 panic!(
72 "Controller type '{}' is already registered. Each controller type must have a unique name.",
73 name
74 );
75 }
76
77 factories.insert(name.to_string(), factory);
78 tracing::debug!("Registered controller type: {}", name);
79 }
80
81 pub fn create_controller(&self, name: &str) -> Result<Box<dyn ElifController>, BootstrapError> {
90 let factories = self.factories.read()
91 .expect("Controller type registry lock poisoned");
92
93 let factory = factories.get(name)
94 .ok_or_else(|| BootstrapError::ControllerNotFound {
95 controller_name: name.to_string(),
96 available_controllers: factories.keys().cloned().collect(),
97 })?;
98
99 let controller = factory();
100 tracing::debug!("Created controller instance: {}", name);
101 Ok(controller)
102 }
103
104 pub fn is_registered(&self, name: &str) -> bool {
106 let factories = self.factories.read()
107 .expect("Controller type registry lock poisoned");
108 factories.contains_key(name)
109 }
110
111 pub fn get_registered_types(&self) -> Vec<String> {
113 let factories = self.factories.read()
114 .expect("Controller type registry lock poisoned");
115 factories.keys().cloned().collect()
116 }
117
118 pub fn count(&self) -> usize {
120 let factories = self.factories.read()
121 .expect("Controller type registry lock poisoned");
122 factories.len()
123 }
124
125 #[cfg(test)]
129 pub fn clear(&self) {
130 let mut factories = self.factories.write()
131 .expect("Controller type registry lock poisoned");
132 factories.clear();
133 tracing::debug!("Cleared all registered controller types");
134 }
135}
136
137pub static CONTROLLER_TYPE_REGISTRY: Lazy<ControllerTypeRegistry> = Lazy::new(ControllerTypeRegistry::new);
142
143pub fn register_controller_type(name: &str, factory: ControllerFactory) {
151 CONTROLLER_TYPE_REGISTRY.register(name, factory);
152}
153
154pub fn create_controller(name: &str) -> Result<Box<dyn ElifController>, BootstrapError> {
163 CONTROLLER_TYPE_REGISTRY.create_controller(name)
164}
165
166pub fn create_controller_instance<T>() -> Box<dyn ElifController>
171where
172 T: ElifController + Default + 'static,
173{
174 Box::new(T::default()) as Box<dyn ElifController>
175}
176
177pub fn create_ioc_controller_instance<T>() -> Box<dyn ElifController>
182where
183 T: ElifController + crate::controller::factory::IocControllable + 'static,
184{
185 let container = elif_core::container::IocContainer::new();
187
188 match T::from_ioc_container(&container, None) {
190 Ok(controller) => Box::new(controller) as Box<dyn ElifController>,
191 Err(e) => {
192 tracing::error!("Failed to create IoC controller: {}", e);
194 panic!(
195 "Auto-registration failed for controller {}. Error: {}\n\
196 Consider:\n\
197 1. Implementing Default for all dependencies\n\
198 2. Using router.controller_from_container::<T>() with proper IoC setup\n\
199 3. Registering dependencies in IoC container before controller registration",
200 std::any::type_name::<T>(),
201 e
202 );
203 }
204 }
205}
206
207#[macro_export]
214macro_rules! __controller_auto_register {
215 ($name:expr, $type:ty) => {
216 const _: () = {
219 #[::ctor::ctor]
220 fn __register_controller() {
221 $crate::bootstrap::controller_registry::register_controller_type(
222 $name,
223 || {
224 $crate::bootstrap::controller_registry::create_controller_instance::<$type>()
227 }
228 );
229 }
230 };
231 };
232}
233
234#[macro_export]
239macro_rules! __controller_auto_register_ioc {
240 ($name:expr, $type:ty) => {
241 const _: () = {
244 #[::ctor::ctor]
245 fn __register_controller() {
246 $crate::bootstrap::controller_registry::register_controller_type(
247 $name,
248 || {
249 $crate::bootstrap::controller_registry::create_ioc_controller_instance::<$type>()
252 }
253 );
254 }
255 };
256 };
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262 use crate::controller::{ElifController, ControllerRoute};
263 use crate::{ElifRequest, ElifResponse, HttpResult};
264 use crate::routing::HttpMethod;
265 use async_trait::async_trait;
266 use std::sync::Arc;
267
268 #[derive(Debug)]
270 struct TestController {
271 name: String,
272 }
273
274 impl TestController {
275 fn new() -> Self {
276 Self {
277 name: "TestController".to_string(),
278 }
279 }
280 }
281
282 #[async_trait]
283 impl ElifController for TestController {
284 fn name(&self) -> &str {
285 &self.name
286 }
287
288 fn base_path(&self) -> &str {
289 "/test"
290 }
291
292 fn routes(&self) -> Vec<ControllerRoute> {
293 vec![
294 ControllerRoute {
295 method: HttpMethod::GET,
296 path: "".to_string(),
297 handler_name: "index".to_string(),
298 middleware: vec![],
299 params: vec![],
300 }
301 ]
302 }
303
304 fn dependencies(&self) -> Vec<String> {
305 vec![]
306 }
307
308 async fn handle_request(
309 self: Arc<Self>,
310 _method_name: String,
311 _request: ElifRequest,
312 ) -> HttpResult<ElifResponse> {
313 Ok(ElifResponse::ok())
314 }
315 }
316
317 #[test]
318 fn test_controller_type_registry_creation() {
319 let registry = ControllerTypeRegistry::new();
320 assert_eq!(registry.count(), 0);
321 assert!(registry.get_registered_types().is_empty());
322 }
323
324 #[test]
325 fn test_controller_registration() {
326 let registry = ControllerTypeRegistry::new();
327
328 registry.register("TestController", || Box::new(TestController::new()));
330
331 assert_eq!(registry.count(), 1);
332 assert!(registry.is_registered("TestController"));
333 assert!(!registry.is_registered("NonExistentController"));
334
335 let types = registry.get_registered_types();
336 assert_eq!(types.len(), 1);
337 assert!(types.contains(&"TestController".to_string()));
338 }
339
340 #[test]
341 fn test_controller_creation() {
342 let registry = ControllerTypeRegistry::new();
343
344 registry.register("TestController", || Box::new(TestController::new()));
346
347 let result = registry.create_controller("TestController");
349 assert!(result.is_ok());
350
351 let controller = result.unwrap();
352 assert_eq!(controller.name(), "TestController");
353 assert_eq!(controller.base_path(), "/test");
354 assert_eq!(controller.routes().len(), 1);
355 }
356
357 #[test]
358 fn test_controller_not_found() {
359 let registry = ControllerTypeRegistry::new();
360
361 let result = registry.create_controller("NonExistentController");
362 assert!(result.is_err());
363
364 if let Err(BootstrapError::ControllerNotFound { controller_name, available_controllers }) = result {
365 assert_eq!(controller_name, "NonExistentController");
366 assert_eq!(available_controllers.len(), 0);
367 } else {
368 panic!("Expected ControllerNotFound error");
369 }
370 }
371
372 #[test]
373 #[should_panic(expected = "Controller type 'TestController' is already registered")]
374 fn test_duplicate_registration() {
375 let registry = ControllerTypeRegistry::new();
376
377 registry.register("TestController", || Box::new(TestController::new()));
379 registry.register("TestController", || Box::new(TestController::new()));
380 }
381
382 #[test]
383 fn test_global_registry_functions() {
384 #[cfg(test)]
386 CONTROLLER_TYPE_REGISTRY.clear();
387
388 register_controller_type("GlobalTestController", || Box::new(TestController::new()));
390
391 assert!(CONTROLLER_TYPE_REGISTRY.is_registered("GlobalTestController"));
392 assert_eq!(CONTROLLER_TYPE_REGISTRY.count(), 1);
393
394 let result = create_controller("GlobalTestController");
396 assert!(result.is_ok());
397
398 let controller = result.unwrap();
399 assert_eq!(controller.name(), "TestController"); }
401}