elif_core/container/
registry.rs

1use crate::container::scope::ServiceScope;
2use crate::errors::CoreError;
3use crate::foundation::traits::Service;
4use std::any::{Any, TypeId};
5use std::collections::HashMap;
6use std::sync::{Arc, RwLock};
7
8/// Service entry in the registry
9pub enum ServiceEntry {
10    /// Single instance (singleton)
11    Instance(Arc<dyn Any + Send + Sync>),
12    /// Factory function for creating instances
13    Factory(Box<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync>),
14}
15
16impl std::fmt::Debug for ServiceEntry {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        match self {
19            ServiceEntry::Instance(_) => f.debug_tuple("Instance").field(&"<instance>").finish(),
20            ServiceEntry::Factory(_) => f.debug_tuple("Factory").field(&"<factory>").finish(),
21        }
22    }
23}
24
25/// Registry for managing service instances and factories
26#[derive(Debug)]
27pub struct ServiceRegistry {
28    services: Arc<RwLock<HashMap<TypeId, ServiceEntry>>>,
29    scopes: Arc<RwLock<HashMap<TypeId, ServiceScope>>>,
30}
31
32impl ServiceRegistry {
33    /// Create a new service registry
34    pub fn new() -> Self {
35        Self {
36            services: Arc::new(RwLock::new(HashMap::new())),
37            scopes: Arc::new(RwLock::new(HashMap::new())),
38        }
39    }
40
41    /// Register a service instance
42    pub fn register_service<T>(&mut self, service: T) -> Result<(), CoreError>
43    where
44        T: Service + Clone + 'static,
45    {
46        let type_id = TypeId::of::<T>();
47        let arc_service = Arc::new(service);
48
49        let mut services = self.services.write().map_err(|_| CoreError::LockError {
50            resource: "service_registry".to_string(),
51        })?;
52
53        let mut scopes = self.scopes.write().map_err(|_| CoreError::LockError {
54            resource: "service_scopes".to_string(),
55        })?;
56
57        services.insert(type_id, ServiceEntry::Instance(arc_service));
58        scopes.insert(type_id, ServiceScope::Singleton);
59
60        Ok(())
61    }
62
63    /// Register a singleton service
64    pub fn register_singleton<T>(&mut self, service: T) -> Result<(), CoreError>
65    where
66        T: Service + Clone + 'static,
67    {
68        let type_id = TypeId::of::<T>();
69        let arc_service = Arc::new(service);
70
71        let mut services = self.services.write().map_err(|_| CoreError::LockError {
72            resource: "service_registry".to_string(),
73        })?;
74
75        let mut scopes = self.scopes.write().map_err(|_| CoreError::LockError {
76            resource: "service_scopes".to_string(),
77        })?;
78
79        services.insert(type_id, ServiceEntry::Instance(arc_service));
80        scopes.insert(type_id, ServiceScope::Singleton);
81
82        Ok(())
83    }
84
85    /// Register a transient service factory
86    pub fn register_transient<T>(
87        &mut self,
88        factory: Box<dyn Fn() -> T + Send + Sync>,
89    ) -> Result<(), CoreError>
90    where
91        T: Service + 'static,
92    {
93        let type_id = TypeId::of::<T>();
94
95        let wrapped_factory: Box<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync> =
96            Box::new(move || -> Box<dyn Any + Send + Sync> { Box::new(factory()) });
97
98        let mut services = self.services.write().map_err(|_| CoreError::LockError {
99            resource: "service_registry".to_string(),
100        })?;
101
102        let mut scopes = self.scopes.write().map_err(|_| CoreError::LockError {
103            resource: "service_scopes".to_string(),
104        })?;
105
106        services.insert(type_id, ServiceEntry::Factory(wrapped_factory));
107        scopes.insert(type_id, ServiceScope::Transient);
108
109        Ok(())
110    }
111
112    /// Resolve a service instance
113    pub fn resolve<T>(&self) -> Result<Arc<T>, CoreError>
114    where
115        T: Service + Clone + 'static,
116    {
117        self.try_resolve::<T>()
118            .ok_or_else(|| CoreError::ServiceNotFound {
119                service_type: std::any::type_name::<T>().to_string(),
120            })
121    }
122
123    /// Try to resolve a service instance
124    pub fn try_resolve<T>(&self) -> Option<Arc<T>>
125    where
126        T: Service + Clone + 'static,
127    {
128        let type_id = TypeId::of::<T>();
129        let services = self.services.read().ok()?;
130
131        match services.get(&type_id)? {
132            ServiceEntry::Instance(instance) => {
133                // Clone the Arc itself, not the service - this maintains singleton behavior
134                instance.clone().downcast::<T>().ok()
135            }
136            ServiceEntry::Factory(factory) => {
137                let instance = factory();
138                let boxed = instance.downcast::<T>().ok()?;
139                Some(Arc::new(*boxed))
140            }
141        }
142    }
143
144    /// Check if a service type is registered
145    pub fn contains<T>(&self) -> bool
146    where
147        T: Service + 'static,
148    {
149        let type_id = TypeId::of::<T>();
150        self.services
151            .read()
152            .map(|services| services.contains_key(&type_id))
153            .unwrap_or(false)
154    }
155
156    /// Get the number of registered services
157    pub fn service_count(&self) -> usize {
158        self.services
159            .read()
160            .map(|services| services.len())
161            .unwrap_or(0)
162    }
163
164    /// Get all registered service type IDs
165    pub fn registered_services(&self) -> Vec<TypeId> {
166        self.services
167            .read()
168            .map(|services| services.keys().cloned().collect())
169            .unwrap_or_default()
170    }
171
172    /// Validate all registered services
173    pub fn validate(&self) -> Result<(), CoreError> {
174        // For now, just check that we can acquire read locks
175        let _services = self.services.read().map_err(|_| CoreError::LockError {
176            resource: "service_registry".to_string(),
177        })?;
178
179        let _scopes = self.scopes.read().map_err(|_| CoreError::LockError {
180            resource: "service_scopes".to_string(),
181        })?;
182
183        Ok(())
184    }
185
186    /// Initialize all services that implement Initializable
187    pub async fn initialize_all(&self) -> Result<(), CoreError> {
188        // This is a simplified version - in a real implementation,
189        // we would need to handle service dependencies and initialization order
190        self.validate()
191    }
192}
193
194impl Default for ServiceRegistry {
195    fn default() -> Self {
196        Self::new()
197    }
198}
199
200#[cfg(test)]
201mod tests {
202    use super::*;
203    use crate::foundation::traits::Service;
204    use std::sync::atomic::{AtomicUsize, Ordering};
205
206    #[derive(Debug, Clone)]
207    struct TestService {
208        id: usize,
209        counter: Arc<AtomicUsize>,
210    }
211
212    impl TestService {
213        fn new() -> Self {
214            static COUNTER: AtomicUsize = AtomicUsize::new(0);
215            Self {
216                id: COUNTER.fetch_add(1, Ordering::SeqCst),
217                counter: Arc::new(AtomicUsize::new(0)),
218            }
219        }
220
221        fn increment(&self) -> usize {
222            self.counter.fetch_add(1, Ordering::SeqCst) + 1
223        }
224
225        fn get_count(&self) -> usize {
226            self.counter.load(Ordering::SeqCst)
227        }
228    }
229
230    impl crate::foundation::traits::FrameworkComponent for TestService {}
231
232    impl Service for TestService {}
233
234    #[test]
235    fn test_singleton_behavior() {
236        let mut registry = ServiceRegistry::new();
237        let service = TestService::new();
238        let original_id = service.id;
239
240        // Register as singleton
241        registry.register_singleton(service).unwrap();
242
243        // Resolve multiple times
244        let instance1 = registry.resolve::<TestService>().unwrap();
245        let instance2 = registry.resolve::<TestService>().unwrap();
246        let instance3 = registry.resolve::<TestService>().unwrap();
247
248        // All instances should have the same ID (same original service)
249        assert_eq!(instance1.id, original_id);
250        assert_eq!(instance2.id, original_id);
251        assert_eq!(instance3.id, original_id);
252
253        // Increment counter on one instance
254        let count1 = instance1.increment();
255        assert_eq!(count1, 1);
256
257        // Other instances should see the same count (shared state)
258        assert_eq!(instance2.get_count(), 1);
259        assert_eq!(instance3.get_count(), 1);
260
261        // Increment on another instance
262        let count2 = instance2.increment();
263        assert_eq!(count2, 2);
264
265        // All should see the updated count
266        assert_eq!(instance1.get_count(), 2);
267        assert_eq!(instance3.get_count(), 2);
268    }
269
270    #[test]
271    fn test_singleton_arc_sharing() {
272        let mut registry = ServiceRegistry::new();
273        let service = TestService::new();
274
275        registry.register_singleton(service).unwrap();
276
277        // Resolve multiple times
278        let instance1 = registry.resolve::<TestService>().unwrap();
279        let instance2 = registry.resolve::<TestService>().unwrap();
280
281        // The Arc pointers should be the same (true singleton)
282        assert!(Arc::ptr_eq(&instance1, &instance2));
283    }
284
285    #[test]
286    fn test_transient_behavior() {
287        let mut registry = ServiceRegistry::new();
288
289        // Register transient factory
290        registry
291            .register_transient::<TestService>(Box::new(|| TestService::new()))
292            .unwrap();
293
294        // Resolve multiple times
295        let instance1 = registry.resolve::<TestService>().unwrap();
296        let instance2 = registry.resolve::<TestService>().unwrap();
297
298        // Each instance should have different IDs (new instances)
299        assert_ne!(instance1.id, instance2.id);
300
301        // The Arc pointers should be different (different instances)
302        assert!(!Arc::ptr_eq(&instance1, &instance2));
303
304        // Increment on one should not affect the other
305        instance1.increment();
306        assert_eq!(instance1.get_count(), 1);
307        assert_eq!(instance2.get_count(), 0);
308    }
309
310    #[test]
311    fn test_service_registry_operations() {
312        let mut registry = ServiceRegistry::new();
313        let service = TestService::new();
314
315        // Initially empty
316        assert!(!registry.contains::<TestService>());
317        assert_eq!(registry.service_count(), 0);
318
319        // Register service
320        registry.register_singleton(service).unwrap();
321
322        // Should now contain the service
323        assert!(registry.contains::<TestService>());
324        assert_eq!(registry.service_count(), 1);
325
326        // Should be able to resolve
327        let resolved = registry.resolve::<TestService>().unwrap();
328        assert_eq!(
329            resolved.service_id(),
330            "elif_core::container::registry::tests::TestService"
331        );
332    }
333}