elif_http/bootstrap/
controller_registry.rs

1//! Controller Type Registry for runtime controller resolution
2//!
3//! This module implements a compile-time controller type registry that enables
4//! runtime controller instantiation from string names, overcoming Rust's type
5//! system limitations with trait object resolution.
6//!
7//! ## Architecture
8//!
9//! - `ControllerTypeRegistry`: Global registry of controller factory functions
10//! - `ControllerFactory`: Type-erased factory function for controller creation
11//! - `CONTROLLER_TYPE_REGISTRY`: Thread-safe global instance
12//!
13//! ## Usage
14//!
15//! Controllers are automatically registered via the `#[controller]` macro:
16//!
17//! ```rust
18//! #[controller("/api/users")]
19//! pub struct UserController;
20//! 
21//! // Macro generates registration call:
22//! // CONTROLLER_TYPE_REGISTRY.register("UserController", || Box::new(UserController::new()));
23//! ```
24//!
25//! The registry then enables runtime resolution:
26//!
27//! ```rust
28//! let controller = CONTROLLER_TYPE_REGISTRY.create_controller("UserController")?;
29//! ```
30
31use std::collections::HashMap;
32use std::sync::RwLock;
33use once_cell::sync::Lazy;
34use crate::controller::ElifController;
35use crate::bootstrap::BootstrapError;
36
37/// Type-erased factory function for creating controller instances
38pub type ControllerFactory = fn() -> Box<dyn ElifController>;
39
40/// Thread-safe controller type registry for runtime resolution
41#[derive(Debug)]
42pub struct ControllerTypeRegistry {
43    /// Map of controller type name to factory function
44    factories: RwLock<HashMap<String, ControllerFactory>>,
45}
46
47impl ControllerTypeRegistry {
48    /// Create a new empty controller type registry
49    fn new() -> Self {
50        Self {
51            factories: RwLock::new(HashMap::new()),
52        }
53    }
54
55    /// Register a controller type with its factory function
56    ///
57    /// This is typically called by the `#[controller]` macro during compilation
58    /// to register controller types for runtime resolution.
59    ///
60    /// # Arguments
61    /// * `name` - Controller type name (e.g., "UserController")
62    /// * `factory` - Factory function that creates controller instances
63    ///
64    /// # Panics
65    /// Panics if a controller with the same name is already registered
66    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    /// Create a new controller instance by type name
82    ///
83    /// # Arguments
84    /// * `name` - Controller type name to instantiate
85    ///
86    /// # Returns
87    /// * `Ok(Box<dyn ElifController>)` - New controller instance
88    /// * `Err(BootstrapError)` - If controller type is not registered
89    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    /// Check if a controller type is registered
105    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    /// Get all registered controller type names
112    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    /// Get the total number of registered controller types
119    pub fn count(&self) -> usize {
120        let factories = self.factories.read()
121            .expect("Controller type registry lock poisoned");
122        factories.len()
123    }
124
125    /// Clear all registered controller types
126    ///
127    /// This is primarily useful for testing purposes
128    #[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
137/// Global controller type registry instance
138///
139/// This is automatically populated by the `#[controller]` macro during compilation
140/// and used by the controller auto-registration system at runtime.
141pub static CONTROLLER_TYPE_REGISTRY: Lazy<ControllerTypeRegistry> = Lazy::new(ControllerTypeRegistry::new);
142
143/// Convenience function to register a controller type
144///
145/// This is used by the `#[controller]` macro to register controller types.
146///
147/// # Arguments
148/// * `name` - Controller type name
149/// * `factory` - Factory function that creates controller instances
150pub fn register_controller_type(name: &str, factory: ControllerFactory) {
151    CONTROLLER_TYPE_REGISTRY.register(name, factory);
152}
153
154/// Convenience function to create a controller instance
155///
156/// # Arguments
157/// * `name` - Controller type name to instantiate
158///
159/// # Returns
160/// * `Ok(Box<dyn ElifController>)` - New controller instance
161/// * `Err(BootstrapError)` - If controller type is not registered
162pub fn create_controller(name: &str) -> Result<Box<dyn ElifController>, BootstrapError> {
163    CONTROLLER_TYPE_REGISTRY.create_controller(name)
164}
165
166/// Create a controller instance using Default trait
167///
168/// This function requires controllers to implement Default for auto-registration.
169/// Controllers with dependencies should implement IocControllable instead.
170pub 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
177/// Create an IoC controller instance using IocControllable trait
178///
179/// This function attempts to create a controller with dependencies using
180/// a minimal IoC container or Default implementations.
181pub fn create_ioc_controller_instance<T>() -> Box<dyn ElifController>
182where
183    T: ElifController + crate::controller::factory::IocControllable + 'static,
184{
185    // Create a minimal IoC container for dependency resolution
186    let container = elif_core::container::IocContainer::new();
187    
188    // Try to create the controller using the IocControllable trait
189    match T::from_ioc_container(&container, None) {
190        Ok(controller) => Box::new(controller) as Box<dyn ElifController>,
191        Err(e) => {
192            // Log the error and provide a helpful panic message
193            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/// Helper macro for auto-registering controllers
208///
209/// This macro is used by the #[controller] derive macro to automatically
210/// register controller types at static initialization time using ctor.
211/// It handles both simple controllers (with parameterless new()) and 
212/// IoC-enabled controllers (implementing IocControllable).
213#[macro_export]
214macro_rules! __controller_auto_register {
215    ($name:expr, $type:ty) => {
216        // Use ctor to run registration at static initialization time
217        // This ensures controllers are registered before main() runs
218        const _: () = {
219            #[::ctor::ctor]
220            fn __register_controller() {
221                $crate::bootstrap::controller_registry::register_controller_type(
222                    $name,
223                    || {
224                        // Try to create the controller instance
225                        // This requires the controller to implement Default
226                        $crate::bootstrap::controller_registry::create_controller_instance::<$type>()
227                    }
228                );
229            }
230        };
231    };
232}
233
234/// Helper macro for auto-registering IoC controllers
235///
236/// This macro is used for controllers that have dependencies but can be created
237/// using Default implementations of those dependencies.
238#[macro_export]
239macro_rules! __controller_auto_register_ioc {
240    ($name:expr, $type:ty) => {
241        // Use ctor to run registration at static initialization time
242        // This ensures controllers are registered before main() runs
243        const _: () = {
244            #[::ctor::ctor]
245            fn __register_controller() {
246                $crate::bootstrap::controller_registry::register_controller_type(
247                    $name,
248                    || {
249                        // Try to create the controller instance using IoC container pattern
250                        // This will use the IocControllable trait implementation
251                        $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    // Mock controller for testing
269    #[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        // Register test controller
329        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        // Register test controller
345        registry.register("TestController", || Box::new(TestController::new()));
346        
347        // Create controller instance
348        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        // Register the same controller twice
378        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        // Clear any existing registrations from other tests
385        #[cfg(test)]
386        CONTROLLER_TYPE_REGISTRY.clear();
387        
388        // Test registration via convenience function
389        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        // Test creation via convenience function
395        let result = create_controller("GlobalTestController");
396        assert!(result.is_ok());
397        
398        let controller = result.unwrap();
399        assert_eq!(controller.name(), "TestController"); // TestController returns "TestController" as name
400    }
401}