ferrous_di/collection/
mod.rs

1//! Service collection module for dependency injection.
2//!
3//! This module contains the ServiceCollection type and related functionality
4//! for registering services and building service providers.
5
6use std::any::TypeId;
7use std::sync::Arc;
8
9use crate::{DiResult, DiError, Key, Lifetime, ServiceDescriptor, DiObserver};
10use crate::registration::{Registry, Registration, AnyArc};
11use crate::provider::ResolverContext;
12use crate::observer::Observers;
13use crate::prewarm::PrewarmSet;
14use crate::capabilities::CapabilityRegistry;
15use crate::ServiceProvider;
16
17
18pub mod module_system;
19pub use module_system::*;
20
21pub struct ServiceCollection {
22    registry: Registry,
23    observers: Observers,
24    prewarm: PrewarmSet,
25    pub(crate) capabilities: CapabilityRegistry,
26}
27
28impl ServiceCollection {
29    /// Creates a new empty service collection.
30    pub fn new() -> Self {
31        Self {
32            registry: Registry::new(),
33            observers: Observers::new(),
34            prewarm: PrewarmSet::new(),
35            capabilities: CapabilityRegistry::new(),
36        }
37    }
38    
39    // ----- Concrete Type Registrations -----
40    
41    /// Registers a singleton instance that will be shared across the entire application.
42    /// 
43    /// The instance is created immediately and wrapped in an `Arc` for thread-safe sharing.
44    /// All requests for this service type will return the same instance.
45    ///
46    /// # Examples
47    ///
48    /// ```rust
49    /// # use ferrous_di::ServiceCollection;
50    /// struct Config { 
51    ///     database_url: String 
52    /// }
53    ///
54    /// let mut services = ServiceCollection::new();
55    /// services.add_singleton(Config {
56    ///     database_url: "postgres://localhost".to_string()
57    /// });
58    /// ```
59    pub fn add_singleton<T: 'static + Send + Sync>(&mut self, value: T) -> &mut Self {
60        let arc = Arc::new(value);
61        let key = Key::Type(TypeId::of::<T>(), std::any::type_name::<T>());
62        let ctor = move |_: &ResolverContext| -> DiResult<AnyArc> {
63            Ok(arc.clone())
64        };
65        self.registry.insert(key, Registration::with_metadata(
66            Lifetime::Singleton,
67            Arc::new(ctor),
68            None,
69            Some(TypeId::of::<T>()),
70        ));
71        self
72    }
73    
74    /// Registers a singleton factory that creates the instance on first request.
75    ///
76    /// The factory is called only once, and the result is cached and shared across
77    /// all subsequent requests. The factory receives a `ResolverContext` to resolve
78    /// dependencies.
79    ///
80    /// # Examples
81    ///
82    /// ```rust
83    /// # use ferrous_di::{ServiceCollection, Resolver};
84    /// # use std::sync::Arc;
85    /// struct Database { url: String }
86    /// struct UserService { db: Arc<Database> }
87    ///
88    /// let mut services = ServiceCollection::new();
89    /// services.add_singleton(Database { url: "postgres://localhost".to_string() });
90    /// services.add_singleton_factory::<UserService, _>(|resolver| {
91    ///     UserService {
92    ///         db: resolver.get_required::<Database>()
93    ///     }
94    /// });
95    /// ```
96    pub fn add_singleton_factory<T, F>(&mut self, factory: F) -> &mut Self
97    where
98        T: 'static + Send + Sync,
99        F: Fn(&ResolverContext) -> T + Send + Sync + 'static,
100    {
101        self.add_factory(Lifetime::Singleton, factory)
102    }
103    
104    /// Registers a scoped factory that creates one instance per scope.
105    ///
106    /// Each scope gets its own instance, but within a scope, the same instance
107    /// is reused. Perfect for per-request services in web applications.
108    ///
109    /// # Examples
110    ///
111    /// ```rust
112    /// # use ferrous_di::{ServiceCollection, Resolver};
113    /// # use std::sync::Arc;
114    /// struct Database { url: String }
115    /// struct RequestContext { request_id: String }
116    /// struct UserService { db: Arc<Database>, context: Arc<RequestContext> }
117    ///
118    /// let mut services = ServiceCollection::new();
119    /// services.add_singleton(Database { url: "postgres://localhost".to_string() });
120    /// services.add_scoped_factory::<RequestContext, _>(|_| {
121    ///     RequestContext { request_id: "req-123".to_string() }
122    /// });
123    /// services.add_scoped_factory::<UserService, _>(|resolver| {
124    ///     UserService {
125    ///         db: resolver.get_required::<Database>(),
126    ///         context: resolver.get_required::<RequestContext>()
127    ///     }
128    /// });
129    /// ```
130    pub fn add_scoped_factory<T, F>(&mut self, factory: F) -> &mut Self
131    where
132        T: 'static + Send + Sync,
133        F: Fn(&ResolverContext) -> T + Send + Sync + 'static,
134    {
135        self.add_factory(Lifetime::Scoped, factory)
136    }
137    
138    /// Registers a transient factory that creates a new instance on every request.
139    ///
140    /// No caching is performed - the factory is called every time this service
141    /// is resolved, even within the same scope.
142    ///
143    /// # Examples
144    ///
145    /// ```rust
146    /// # use ferrous_di::{ServiceCollection, Resolver};
147    /// # use std::sync::Arc;
148    /// struct Database { url: String }
149    /// struct Logger { timestamp: std::time::SystemTime }
150    ///
151    /// let mut services = ServiceCollection::new();
152    /// services.add_singleton(Database { url: "postgres://localhost".to_string() });
153    /// services.add_transient_factory::<Logger, _>(|_| {
154    ///     Logger { timestamp: std::time::SystemTime::now() }
155    /// });
156    /// ```
157    pub fn add_transient_factory<T, F>(&mut self, factory: F) -> &mut Self
158    where
159        T: 'static + Send + Sync,
160        F: Fn(&ResolverContext) -> T + Send + Sync + 'static,
161    {
162        self.add_factory(Lifetime::Transient, factory)
163    }
164    
165    fn add_factory<T, F>(&mut self, lifetime: Lifetime, factory: F) -> &mut Self
166    where
167        T: 'static + Send + Sync,
168        F: Fn(&ResolverContext) -> T + Send + Sync + 'static,
169    {
170        let key = Key::Type(TypeId::of::<T>(), std::any::type_name::<T>());
171        let factory = Arc::new(factory);
172        let ctor = move |r: &ResolverContext| -> DiResult<AnyArc> {
173            // Let factories run - circular dependencies will panic with CircularPanic
174            // All other panics (including from get_required) will be caught at the top level
175            Ok(Arc::new(factory(r)))
176        };
177        self.registry.insert(key, Registration::with_metadata(
178            lifetime,
179            Arc::new(ctor),
180            None,
181            Some(TypeId::of::<T>()),
182        ));
183        self
184    }
185    
186    // ----- Trait Single-Binding Registrations -----
187    
188    /// Registers a singleton trait implementation.
189    ///
190    /// Binds a concrete implementation to a trait, creating a single instance
191    /// that's shared across the entire application. The implementation must
192    /// already be wrapped in an `Arc`.
193    ///
194    /// # Examples
195    ///
196    /// ```rust
197    /// # use ferrous_di::{ServiceCollection, Resolver};
198    /// # use std::sync::Arc;
199    /// trait Logger: Send + Sync {
200    ///     fn log(&self, message: &str);
201    /// }
202    ///
203    /// struct FileLogger { path: String }
204    /// impl Logger for FileLogger {
205    ///     fn log(&self, message: &str) {
206    ///         // Write to file
207    ///     }
208    /// }
209    ///
210    /// let mut services = ServiceCollection::new();
211    /// let logger = Arc::new(FileLogger { path: "/var/log/app.log".to_string() });
212    /// services.add_singleton_trait::<dyn Logger>(logger);
213    /// ```
214    pub fn add_singleton_trait<T>(&mut self, value: Arc<T>) -> &mut Self
215    where
216        T: ?Sized + 'static + Send + Sync,
217    {
218        let key = Key::Trait(std::any::type_name::<T>());
219        // Expert fix: Store as Arc<Arc<dyn Trait>> in Any
220        let any_arc: AnyArc = Arc::new(value.clone());
221        let ctor = move |_: &ResolverContext| -> DiResult<AnyArc> {
222            Ok(any_arc.clone())
223        };
224        self.registry.insert(key, Registration::with_metadata(
225            Lifetime::Singleton,
226            Arc::new(ctor),
227            None,
228            None, // We don't know the concrete implementation type for trait objects
229        ));
230        self
231    }
232    
233    /// Registers a singleton trait factory.
234    ///
235    /// The factory creates a trait implementation on first request, and the result
236    /// is cached as a singleton. The factory must return an `Arc<Trait>`.
237    ///
238    /// # Examples
239    ///
240    /// ```rust
241    /// # use ferrous_di::{ServiceCollection, Resolver};
242    /// # use std::sync::Arc;
243    /// trait Logger: Send + Sync {
244    ///     fn log(&self, message: &str);
245    /// }
246    ///
247    /// struct FileLogger { path: String }
248    /// impl Logger for FileLogger {
249    ///     fn log(&self, message: &str) {
250    ///         // Write to file
251    ///     }
252    /// }
253    ///
254    /// let mut services = ServiceCollection::new();
255    /// services.add_singleton_trait_factory::<dyn Logger, _>(|_| {
256    ///     Arc::new(FileLogger { path: "/var/log/app.log".to_string() })
257    /// });
258    /// ```
259    pub fn add_singleton_trait_factory<Trait, F>(&mut self, factory: F) -> &mut Self
260    where
261        Trait: ?Sized + 'static + Send + Sync,
262        F: Fn(&ResolverContext) -> Arc<Trait> + Send + Sync + 'static,
263    {
264        self.add_trait_factory_impl(Lifetime::Singleton, factory)
265    }
266    
267    /// Registers a scoped trait factory.
268    ///
269    /// Creates one trait implementation per scope. Within a scope, the same instance
270    /// is reused, but different scopes get different instances.
271    ///
272    /// # Examples
273    ///
274    /// ```rust
275    /// # use ferrous_di::{ServiceCollection, Resolver};
276    /// # use std::sync::Arc;
277    /// trait RequestLogger: Send + Sync {
278    ///     fn log_request(&self, path: &str);
279    /// }
280    ///
281    /// struct FileRequestLogger { 
282    ///     request_id: String,
283    ///     file_handle: std::fs::File 
284    /// }
285    /// impl RequestLogger for FileRequestLogger {
286    ///     fn log_request(&self, path: &str) {
287    ///         // Log with request ID
288    ///     }
289    /// }
290    ///
291    /// let mut services = ServiceCollection::new();
292    /// services.add_scoped_trait_factory::<dyn RequestLogger, _>(|_| {
293    ///     Arc::new(FileRequestLogger { 
294    ///         request_id: "req-456".to_string(),
295    ///         file_handle: std::fs::File::create("/tmp/request.log").unwrap()
296    ///     })
297    /// });
298    /// ```
299    pub fn add_scoped_trait_factory<Trait, F>(&mut self, factory: F) -> &mut Self
300    where
301        Trait: ?Sized + 'static + Send + Sync,
302        F: Fn(&ResolverContext) -> Arc<Trait> + Send + Sync + 'static,
303    {
304        self.add_trait_factory_impl(Lifetime::Scoped, factory)
305    }
306    
307    /// Registers a transient trait factory.
308    ///
309    /// Creates a new trait implementation on every request. No caching is performed,
310    /// making this suitable for lightweight, stateless services.
311    ///
312    /// # Examples
313    ///
314    /// ```rust
315    /// # use ferrous_di::{ServiceCollection, Resolver};
316    /// # use std::sync::Arc;
317    /// trait TimeProvider: Send + Sync {
318    ///     fn now(&self) -> std::time::SystemTime;
319    /// }
320    ///
321    /// struct SystemTimeProvider;
322    /// impl TimeProvider for SystemTimeProvider {
323    ///     fn now(&self) -> std::time::SystemTime {
324    ///         std::time::SystemTime::now()
325    ///     }
326    /// }
327    ///
328    /// let mut services = ServiceCollection::new();
329    /// services.add_transient_trait_factory::<dyn TimeProvider, _>(|_| {
330    ///     Arc::new(SystemTimeProvider)
331    /// });
332    /// ```
333    pub fn add_transient_trait_factory<Trait, F>(&mut self, factory: F) -> &mut Self
334    where
335        Trait: ?Sized + 'static + Send + Sync,
336        F: Fn(&ResolverContext) -> Arc<Trait> + Send + Sync + 'static,
337    {
338        self.add_trait_factory_impl(Lifetime::Transient, factory)
339    }
340    
341    fn add_trait_factory_impl<Trait, F>(&mut self, lifetime: Lifetime, factory: F) -> &mut Self
342    where
343        Trait: ?Sized + 'static + Send + Sync,
344        F: Fn(&ResolverContext) -> Arc<Trait> + Send + Sync + 'static,
345    {
346        let key = Key::Trait(std::any::type_name::<Trait>());
347        let factory = Arc::new(factory);
348        let ctor = move |r: &ResolverContext| -> DiResult<AnyArc> {
349            // Expert fix: Store as Arc<Arc<dyn Trait>> in Any
350            Ok(Arc::new(factory(r)))
351        };
352        self.registry.insert(key, Registration::with_metadata(
353            lifetime,
354            Arc::new(ctor),
355            None,
356            None, // We don't know the concrete implementation type for trait factories
357        ));
358        self
359    }
360    
361    // ----- Trait Multi-Binding Registrations -----
362    
363    /// Add trait implementation to multi-binding list
364    pub fn add_trait_implementation<T>(&mut self, value: Arc<T>, lifetime: Lifetime) -> &mut Self
365    where
366        T: ?Sized + 'static + Send + Sync,
367    {
368        let name = std::any::type_name::<T>();
369        // Expert fix: Store Arc<dyn Trait> INSIDE Any as Arc<Arc<dyn Trait>>
370        let any_arc: AnyArc = Arc::new(value.clone());
371        let ctor = move |_: &ResolverContext| -> DiResult<AnyArc> {
372            Ok(any_arc.clone())
373        };
374        self.registry.many.entry(name).or_default().push(Registration::with_metadata(
375            lifetime,
376            Arc::new(ctor),
377            None,
378            None, // We don't know the concrete implementation type for trait objects
379        ));
380        self
381    }
382    
383    /// Add trait factory to multi-binding list
384    pub fn add_trait_factory<Trait, F>(&mut self, lifetime: Lifetime, factory: F) -> &mut Self
385    where
386        Trait: ?Sized + 'static + Send + Sync,
387        F: Fn(&ResolverContext) -> Arc<Trait> + Send + Sync + 'static,
388    {
389        let name = std::any::type_name::<Trait>();
390        let factory = Arc::new(factory);
391        let ctor = move |r: &ResolverContext| -> DiResult<AnyArc> {
392            // Expert fix: Store as Arc<Arc<dyn Trait>> in Any
393            Ok(Arc::new(factory(r)))
394        };
395        self.registry.many.entry(name).or_default().push(Registration::with_metadata(
396            lifetime,
397            Arc::new(ctor),
398            None,
399            None, // We don't know the concrete implementation type for trait factories
400        ));
401        self
402    }
403    
404    // ----- Service Descriptors and Introspection -----
405    
406    /// Get all service descriptors for introspection and diagnostics.
407    ///
408    /// Returns a vector of `ServiceDescriptor` objects that describe all registered services,
409    /// including their keys, lifetimes, and implementation type information when available.
410    ///
411    /// # Examples
412    ///
413    /// ```
414    /// use ferrous_di::{ServiceCollection, Lifetime};
415    /// use std::sync::Arc;
416    ///
417    /// let mut services = ServiceCollection::new();
418    /// services.add_singleton(42usize);
419    /// services.add_scoped_factory::<String, _>(|_| "hello".to_string());
420    ///
421    /// let descriptors = services.get_service_descriptors();
422    /// assert_eq!(descriptors.len(), 2);
423    /// 
424    /// // Find the usize singleton
425    /// let usize_desc = descriptors.iter()
426    ///     .find(|d| d.type_name().contains("usize"))
427    ///     .unwrap();
428    /// assert_eq!(usize_desc.lifetime, Lifetime::Singleton);
429    /// ```
430    pub fn get_service_descriptors(&self) -> Vec<ServiceDescriptor> {
431        let mut descriptors = Vec::new();
432        
433        // Single-binding services
434        for (key, registration) in self.registry.iter() {
435            descriptors.push(ServiceDescriptor {
436                key: key.clone(),
437                lifetime: registration.lifetime,
438                impl_type_id: registration.impl_id,
439                impl_type_name: registration.impl_id.map(|_| key.display_name()), // Use the key's display name as impl name
440                has_metadata: registration.metadata.is_some(),
441            });
442        }
443        
444        // Multi-binding services
445        for (trait_name, registrations) in &self.registry.many {
446            for (index, registration) in registrations.iter().enumerate() {
447                descriptors.push(ServiceDescriptor {
448                    key: Key::MultiTrait(trait_name, index),
449                    lifetime: registration.lifetime,
450                    impl_type_id: registration.impl_id,
451                    impl_type_name: registration.impl_id.map(|_| *trait_name),
452                    has_metadata: registration.metadata.is_some(),
453                });
454            }
455        }
456        
457        descriptors
458    }
459    
460    /// Register a service with custom metadata.
461    ///
462    /// Metadata can be used for diagnostics, configuration, or other runtime introspection.
463    /// The metadata must implement Send + Sync + 'static.
464    ///
465    /// # Examples
466    ///
467    /// ```
468    /// use ferrous_di::{ServiceCollection, Lifetime};
469    /// use std::sync::Arc;
470    ///
471    /// #[derive(Debug)]
472    /// struct ServiceMetadata {
473    ///     description: String,
474    ///     version: String,
475    /// }
476    ///
477    /// let mut services = ServiceCollection::new();
478    /// services.add_with_metadata(
479    ///     42usize,
480    ///     Lifetime::Singleton,
481    ///     ServiceMetadata {
482    ///         description: "Answer to everything".to_string(),
483    ///         version: "1.0".to_string(),
484    ///     }
485    /// );
486    /// ```
487    pub fn add_with_metadata<T, M>(&mut self, value: T, lifetime: Lifetime, metadata: M) -> &mut Self
488    where
489        T: 'static + Send + Sync,
490        M: Send + Sync + 'static,
491    {
492        let arc = Arc::new(value);
493        let key = Key::Type(TypeId::of::<T>(), std::any::type_name::<T>());
494        let ctor = move |_: &ResolverContext| -> DiResult<AnyArc> {
495            Ok(arc.clone())
496        };
497        self.registry.insert(key, Registration::with_metadata(
498            lifetime,
499            Arc::new(ctor),
500            Some(Box::new(metadata)),
501            Some(TypeId::of::<T>()),
502        ));
503        self
504    }
505    
506    /// Get metadata for a specific service key.
507    ///
508    /// Returns the metadata if it exists and can be downcast to the specified type.
509    ///
510    /// # Examples
511    ///
512    /// ```
513    /// # use ferrous_di::{ServiceCollection, Lifetime, Key};
514    /// # use std::any::TypeId;
515    /// # #[derive(Debug, PartialEq)]
516    /// # struct ServiceMetadata { description: String }
517    /// # let mut services = ServiceCollection::new();
518    /// # services.add_with_metadata(42usize, Lifetime::Singleton, ServiceMetadata { description: "test".to_string() });
519    /// let key = Key::Type(TypeId::of::<usize>(), "usize");
520    /// let metadata = services.get_metadata::<ServiceMetadata>(&key);
521    /// assert!(metadata.is_some());
522    /// ```
523    pub fn get_metadata<M: 'static>(&self, key: &Key) -> Option<&M> {
524        self.registry.get(key)?
525            .metadata.as_ref()?
526            .downcast_ref::<M>()
527    }
528    
529    // ----- Conditional Registration (TryAdd*) -----
530    
531    /// Register a singleton if not already registered.
532    ///
533    /// This method only registers the service if no service of type `T` is currently registered.
534    /// It returns `true` if the service was registered, `false` if it was already registered.
535    ///
536    /// # Examples
537    ///
538    /// ```
539    /// use ferrous_di::ServiceCollection;
540    ///
541    /// let mut services = ServiceCollection::new();
542    /// 
543    /// let registered1 = services.try_add_singleton(42usize);
544    /// assert!(registered1); // First registration succeeds
545    /// 
546    /// let registered2 = services.try_add_singleton(100usize);
547    /// assert!(!registered2); // Second registration is ignored
548    /// ```
549    pub fn try_add_singleton<T: 'static + Send + Sync>(&mut self, value: T) -> bool {
550        let key = Key::Type(TypeId::of::<T>(), std::any::type_name::<T>());
551        if self.registry.contains_key(&key) {
552            false
553        } else {
554            self.add_singleton(value);
555            true
556        }
557    }
558    
559    /// Register a singleton factory if not already registered.
560    pub fn try_add_singleton_factory<T, F>(&mut self, factory: F) -> bool
561    where
562        T: 'static + Send + Sync,
563        F: Fn(&ResolverContext) -> T + Send + Sync + 'static,
564    {
565        let key = Key::Type(TypeId::of::<T>(), std::any::type_name::<T>());
566        if self.registry.contains_key(&key) {
567            false
568        } else {
569            self.add_singleton_factory(factory);
570            true
571        }
572    }
573    
574    /// Register a scoped factory if not already registered.
575    pub fn try_add_scoped_factory<T, F>(&mut self, factory: F) -> bool
576    where
577        T: 'static + Send + Sync,
578        F: Fn(&ResolverContext) -> T + Send + Sync + 'static,
579    {
580        let key = Key::Type(TypeId::of::<T>(), std::any::type_name::<T>());
581        if self.registry.contains_key(&key) {
582            false
583        } else {
584            self.add_scoped_factory(factory);
585            true
586        }
587    }
588    
589    /// Register a transient factory if not already registered.
590    pub fn try_add_transient_factory<T, F>(&mut self, factory: F) -> bool
591    where
592        T: 'static + Send + Sync,
593        F: Fn(&ResolverContext) -> T + Send + Sync + 'static,
594    {
595        let key = Key::Type(TypeId::of::<T>(), std::any::type_name::<T>());
596        if self.registry.contains_key(&key) {
597            false
598        } else {
599            self.add_transient_factory(factory);
600            true
601        }
602    }
603    
604    /// Register a singleton trait if not already registered.
605    pub fn try_add_singleton_trait<T>(&mut self, value: Arc<T>) -> bool
606    where
607        T: ?Sized + 'static + Send + Sync,
608    {
609        let key = Key::Trait(std::any::type_name::<T>());
610        if self.registry.contains_key(&key) {
611            false
612        } else {
613            self.add_singleton_trait(value);
614            true
615        }
616    }
617    
618    /// Register a singleton trait factory if not already registered.
619    pub fn try_add_singleton_trait_factory<Trait, F>(&mut self, factory: F) -> bool
620    where
621        Trait: ?Sized + 'static + Send + Sync,
622        F: Fn(&ResolverContext) -> Arc<Trait> + Send + Sync + 'static,
623    {
624        let key = Key::Trait(std::any::type_name::<Trait>());
625        if self.registry.contains_key(&key) {
626            false
627        } else {
628            self.add_singleton_trait_factory(factory);
629            true
630        }
631    }
632    
633    /// Register a scoped trait factory if not already registered.
634    pub fn try_add_scoped_trait_factory<Trait, F>(&mut self, factory: F) -> bool
635    where
636        Trait: ?Sized + 'static + Send + Sync,
637        F: Fn(&ResolverContext) -> Arc<Trait> + Send + Sync + 'static,
638    {
639        let key = Key::Trait(std::any::type_name::<Trait>());
640        if self.registry.contains_key(&key) {
641            false
642        } else {
643            self.add_scoped_trait_factory(factory);
644            true
645        }
646    }
647    
648    /// Register a transient trait factory if not already registered.
649    pub fn try_add_transient_trait_factory<Trait, F>(&mut self, factory: F) -> bool
650    where
651        Trait: ?Sized + 'static + Send + Sync,
652        F: Fn(&ResolverContext) -> Arc<Trait> + Send + Sync + 'static,
653    {
654        let key = Key::Trait(std::any::type_name::<Trait>());
655        if self.registry.contains_key(&key) {
656            false
657        } else {
658            self.add_transient_trait_factory(factory);
659            true
660        }
661    }
662    
663    /// Add enumerable trait registration (always adds, doesn't check for existing).
664    ///
665    /// This method is equivalent to `add_trait_implementation` but with a name that matches
666    /// Microsoft.Extensions.DependencyInjection conventions.
667    pub fn try_add_enumerable<T>(&mut self, value: Arc<T>, lifetime: Lifetime) -> &mut Self
668    where
669        T: ?Sized + 'static + Send + Sync,
670    {
671        // For enumerable services, we always add (no conditional logic)
672        self.add_trait_implementation(value, lifetime)
673    }
674    
675    // ----- Named Service Registration -----
676    
677    /// Register a named singleton service.
678    ///
679    /// Named services allow multiple registrations of the same type distinguished by name.
680    /// This is useful for scenarios like multiple database connections, different configurations, etc.
681    ///
682    /// # Examples
683    ///
684    /// ```
685    /// use ferrous_di::ServiceCollection;
686    ///
687    /// let mut services = ServiceCollection::new();
688    /// services.add_named_singleton("primary", 42usize);
689    /// services.add_named_singleton("secondary", 100usize);
690    /// 
691    /// let provider = services.build();
692    /// // These would be resolved separately by name
693    /// ```
694    pub fn add_named_singleton<T: 'static + Send + Sync>(&mut self, name: &'static str, value: T) -> &mut Self {
695        let arc = Arc::new(value);
696        let key = Key::TypeNamed(TypeId::of::<T>(), std::any::type_name::<T>(), name);
697        let ctor = move |_: &ResolverContext| -> DiResult<AnyArc> {
698            Ok(arc.clone())
699        };
700        self.registry.insert(key, Registration::with_metadata(
701            Lifetime::Singleton,
702            Arc::new(ctor),
703            None,
704            Some(TypeId::of::<T>()),
705        ));
706        self
707    }
708    
709    /// Register a named singleton factory.
710    pub fn add_named_singleton_factory<T, F>(&mut self, name: &'static str, factory: F) -> &mut Self
711    where
712        T: 'static + Send + Sync,
713        F: Fn(&ResolverContext) -> T + Send + Sync + 'static,
714    {
715        let key = Key::TypeNamed(TypeId::of::<T>(), std::any::type_name::<T>(), name);
716        let factory = Arc::new(factory);
717        let ctor = move |r: &ResolverContext| -> DiResult<AnyArc> {
718            Ok(Arc::new(factory(r)))
719        };
720        self.registry.insert(key, Registration::with_metadata(
721            Lifetime::Singleton,
722            Arc::new(ctor),
723            None,
724            Some(TypeId::of::<T>()),
725        ));
726        self
727    }
728    
729    /// Register a named scoped factory.
730    pub fn add_named_scoped_factory<T, F>(&mut self, name: &'static str, factory: F) -> &mut Self
731    where
732        T: 'static + Send + Sync,
733        F: Fn(&ResolverContext) -> T + Send + Sync + 'static,
734    {
735        let key = Key::TypeNamed(TypeId::of::<T>(), std::any::type_name::<T>(), name);
736        let factory = Arc::new(factory);
737        let ctor = move |r: &ResolverContext| -> DiResult<AnyArc> {
738            Ok(Arc::new(factory(r)))
739        };
740        self.registry.insert(key, Registration::with_metadata(
741            Lifetime::Scoped,
742            Arc::new(ctor),
743            None,
744            Some(TypeId::of::<T>()),
745        ));
746        self
747    }
748    
749    /// Register a named transient factory.
750    pub fn add_named_transient_factory<T, F>(&mut self, name: &'static str, factory: F) -> &mut Self
751    where
752        T: 'static + Send + Sync,
753        F: Fn(&ResolverContext) -> T + Send + Sync + 'static,
754    {
755        let key = Key::TypeNamed(TypeId::of::<T>(), std::any::type_name::<T>(), name);
756        let factory = Arc::new(factory);
757        let ctor = move |r: &ResolverContext| -> DiResult<AnyArc> {
758            Ok(Arc::new(factory(r)))
759        };
760        self.registry.insert(key, Registration::with_metadata(
761            Lifetime::Transient,
762            Arc::new(ctor),
763            None,
764            Some(TypeId::of::<T>()),
765        ));
766        self
767    }
768    
769    /// Register a named singleton trait.
770    pub fn add_named_singleton_trait<T>(&mut self, name: &'static str, value: Arc<T>) -> &mut Self
771    where
772        T: ?Sized + 'static + Send + Sync,
773    {
774        let key = Key::TraitNamed(std::any::type_name::<T>(), name);
775        let any_arc: AnyArc = Arc::new(value.clone());
776        let ctor = move |_: &ResolverContext| -> DiResult<AnyArc> {
777            Ok(any_arc.clone())
778        };
779        self.registry.insert(key, Registration::with_metadata(
780            Lifetime::Singleton,
781            Arc::new(ctor),
782            None,
783            None, // We don't know the concrete implementation type for trait objects
784        ));
785        self
786    }
787    
788    /// Register a named singleton trait factory.
789    pub fn add_named_singleton_trait_factory<Trait, F>(&mut self, name: &'static str, factory: F) -> &mut Self
790    where
791        Trait: ?Sized + 'static + Send + Sync,
792        F: Fn(&ResolverContext) -> Arc<Trait> + Send + Sync + 'static,
793    {
794        let key = Key::TraitNamed(std::any::type_name::<Trait>(), name);
795        let factory = Arc::new(factory);
796        let ctor = move |r: &ResolverContext| -> DiResult<AnyArc> {
797            Ok(Arc::new(factory(r)))
798        };
799        self.registry.insert(key, Registration::with_metadata(
800            Lifetime::Singleton,
801            Arc::new(ctor),
802            None,
803            None,
804        ));
805        self
806    }
807    
808    /// Register a named scoped trait factory.
809    pub fn add_named_scoped_trait_factory<Trait, F>(&mut self, name: &'static str, factory: F) -> &mut Self
810    where
811        Trait: ?Sized + 'static + Send + Sync,
812        F: Fn(&ResolverContext) -> Arc<Trait> + Send + Sync + 'static,
813    {
814        let key = Key::TraitNamed(std::any::type_name::<Trait>(), name);
815        let factory = Arc::new(factory);
816        let ctor = move |r: &ResolverContext| -> DiResult<AnyArc> {
817            Ok(Arc::new(factory(r)))
818        };
819        self.registry.insert(key, Registration::with_metadata(
820            Lifetime::Scoped,
821            Arc::new(ctor),
822            None,
823            None,
824        ));
825        self
826    }
827    
828    /// Register a named transient trait factory.
829    pub fn add_named_transient_trait_factory<Trait, F>(&mut self, name: &'static str, factory: F) -> &mut Self
830    where
831        Trait: ?Sized + 'static + Send + Sync,
832        F: Fn(&ResolverContext) -> Arc<Trait> + Send + Sync + 'static,
833    {
834        let key = Key::TraitNamed(std::any::type_name::<Trait>(), name);
835        let factory = Arc::new(factory);
836        let ctor = move |r: &ResolverContext| -> DiResult<AnyArc> {
837            Ok(Arc::new(factory(r)))
838        };
839        self.registry.insert(key, Registration::with_metadata(
840            Lifetime::Transient,
841            Arc::new(ctor),
842            None,
843            None,
844        ));
845        self
846    }
847    
848    /// Add named multi-trait registration.
849    pub fn add_named_trait_implementation<T>(&mut self, name: &'static str, value: Arc<T>, lifetime: Lifetime) -> &mut Self
850    where
851        T: ?Sized + 'static + Send + Sync,
852    {
853        let trait_name = std::any::type_name::<T>();
854        let any_arc: AnyArc = Arc::new(value.clone());
855        let ctor = move |_: &ResolverContext| -> DiResult<AnyArc> {
856            Ok(any_arc.clone())
857        };
858        
859        // For named multi-trait, we need to create unique keys with names
860        // We'll use a combination approach: store in many with a combined key
861        let combined_key = format!("{}#{}", trait_name, name);
862        let static_key: &'static str = Box::leak(combined_key.into_boxed_str());
863        
864        self.registry.many.entry(static_key).or_default().push(Registration::with_metadata(
865            lifetime,
866            Arc::new(ctor),
867            None,
868            None,
869        ));
870        self
871    }
872    
873    // ----- Observer Management -----
874    
875    /// Adds a diagnostic observer for DI resolution events.
876    ///
877    /// Observers enable structured tracing and monitoring of the dependency injection
878    /// container's behavior. This is particularly valuable for agentic systems where
879    /// you need to correlate DI events with agent execution steps and debug complex
880    /// resolution chains.
881    ///
882    /// # Performance
883    ///
884    /// Observer calls are made synchronously during resolution. Keep observer
885    /// implementations lightweight to avoid impacting performance.
886    ///
887    /// # Examples
888    ///
889    /// ```
890    /// use ferrous_di::{ServiceCollection, LoggingObserver, DiObserver};
891    /// use std::sync::Arc;
892    ///
893    /// // Using the built-in logging observer
894    /// let mut services = ServiceCollection::new();
895    /// services.add_observer(Arc::new(LoggingObserver::new()));
896    ///
897    /// // Using a custom observer
898    /// struct MetricsObserver {
899    ///     counter: std::sync::Arc<std::sync::atomic::AtomicU64>,
900    /// }
901    ///
902    /// impl DiObserver for MetricsObserver {
903    ///     fn resolving(&self, key: &ferrous_di::Key) {
904    ///         self.counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
905    ///     }
906    ///
907    ///     fn resolved(&self, _key: &ferrous_di::Key, _duration: std::time::Duration) {}
908    ///     fn factory_panic(&self, _key: &ferrous_di::Key, _message: &str) {}
909    /// }
910    ///
911    /// let counter = Arc::new(std::sync::atomic::AtomicU64::new(0));
912    /// services.add_observer(Arc::new(MetricsObserver { counter: counter.clone() }));
913    ///
914    /// let provider = services.build();
915    /// // All resolutions will be observed
916    /// ```
917    pub fn add_observer(&mut self, observer: Arc<dyn DiObserver>) -> &mut Self {
918        self.observers.add(observer);
919        self
920    }
921    
922    // ----- Decoration / Interceptors -----
923    
924    /// Decorates all registrations of a trait with a wrapper function.
925    ///
926    /// This enables cross-cutting concerns like logging, timeouts, retries, rate limiting,
927    /// authentication, and PII scrubbing without modifying the original implementations.
928    /// The decorator function is applied to both single-binding and multi-binding registrations.
929    ///
930    /// This is particularly powerful for agentic systems where you need to apply consistent
931    /// policies across all tools or services.
932    ///
933    /// # Arguments
934    ///
935    /// * `decorator` - A function that takes an `Arc<T>` and returns a wrapped `Arc<T>`
936    ///
937    /// # Examples
938    ///
939    /// ```
940    /// use ferrous_di::{ServiceCollection, Resolver};
941    /// use std::sync::Arc;
942    ///
943    /// trait Tool: Send + Sync {
944    ///     fn execute(&self, input: &str) -> String;
945    /// }
946    ///
947    /// struct FileTool;
948    /// impl Tool for FileTool {
949    ///     fn execute(&self, input: &str) -> String {
950    ///         format!("File operation: {}", input)
951    ///     }
952    /// }
953    ///
954    /// struct LoggingWrapper<T: ?Sized> {
955///     inner: Arc<T>,
956/// }
957///
958/// impl<T: ?Sized> LoggingWrapper<T> {
959///     fn new(inner: Arc<T>) -> Self { Self { inner } }
960/// }
961///
962/// impl<T: Tool + ?Sized> Tool for LoggingWrapper<T> {
963    ///     fn execute(&self, input: &str) -> String {
964    ///         println!("Executing tool with input: {}", input);
965    ///         let result = self.inner.execute(input);
966    ///         println!("Tool result: {}", result);
967    ///         result
968    ///     }
969    /// }
970    ///
971    /// let mut services = ServiceCollection::new();
972    /// 
973    /// // Register tools
974    /// services.add_singleton_trait::<dyn Tool>(Arc::new(FileTool));
975    ///
976    /// // Apply logging to all tools
977    /// services.decorate_trait::<dyn Tool, _>(|tool| {
978    ///     Arc::new(LoggingWrapper::new(tool))
979    /// });
980    ///
981    /// let provider = services.build();
982    /// let tool = provider.get_required_trait::<dyn Tool>();
983    /// let result = tool.execute("test.txt");
984    /// // Logs: "Executing tool with input: test.txt"
985    /// // Logs: "Tool result: File operation: test.txt"
986    /// ```
987    pub fn decorate_trait<T, F>(&mut self, decorator: F) -> &mut Self
988    where
989        T: ?Sized + 'static + Send + Sync,
990        F: Fn(Arc<T>) -> Arc<T> + Send + Sync + 'static,
991    {
992        let trait_name = std::any::type_name::<T>();
993        let decorator = Arc::new(decorator);
994        
995        // Decorate single-binding registration if it exists
996        let single_key = Key::Trait(trait_name);
997        if let Some(registration) = self.registry.get_mut(&single_key) {
998            let old_ctor = registration.ctor.clone();
999            let decorator_clone = decorator.clone();
1000            
1001            registration.ctor = Arc::new(move |resolver| {
1002                // Call original constructor
1003                let original = old_ctor(resolver)?;
1004                
1005                // Cast to the trait type and apply decorator
1006                let typed = original.downcast::<Arc<T>>()
1007                    .map_err(|_| DiError::TypeMismatch(trait_name))?;
1008                let decorated = decorator_clone((*typed).clone());
1009                
1010                // Wrap back in Arc<dyn Any>
1011                Ok(Arc::new(decorated))
1012            });
1013        }
1014        
1015        // Decorate multi-binding registrations if they exist
1016        if let Some(registrations) = self.registry.many.get_mut(trait_name) {
1017            for registration in registrations.iter_mut() {
1018                let old_ctor = registration.ctor.clone();
1019                let decorator_clone = decorator.clone();
1020                
1021                registration.ctor = Arc::new(move |resolver| {
1022                    // Call original constructor
1023                    let original = old_ctor(resolver)?;
1024                    
1025                    // Cast to the trait type and apply decorator
1026                    let typed = original.downcast::<Arc<T>>()
1027                        .map_err(|_| DiError::TypeMismatch(trait_name))?;
1028                    let decorated = decorator_clone((*typed).clone());
1029                    
1030                    // Wrap back in Arc<dyn Any>
1031                    Ok(Arc::new(decorated))
1032                });
1033            }
1034        }
1035        
1036        self
1037    }
1038
1039    /// Decorates a concrete service type with a first-class decorator.
1040    ///
1041    /// This is the modern, type-safe approach to service decoration that provides
1042    /// access to the resolver during decoration. Perfect for workflow engines that
1043    /// need to inject dependencies during decoration.
1044    ///
1045    /// # Examples
1046    ///
1047    /// ```
1048    /// use ferrous_di::{ServiceCollection, ServiceDecorator, Resolver};
1049    /// use std::sync::Arc;
1050    ///
1051    /// struct UserService {
1052    ///     name: String,
1053    /// }
1054    ///
1055    /// struct LoggingDecorator;
1056    ///
1057    /// impl ServiceDecorator<UserService> for LoggingDecorator {
1058    ///     fn decorate(&self, original: Arc<UserService>, _resolver: &dyn ferrous_di::traits::ResolverCore) -> Arc<UserService> {
1059    ///         println!("Accessing user: {}", original.name);
1060    ///         original
1061    ///     }
1062    /// }
1063    ///
1064    /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
1065    /// let mut services = ServiceCollection::new();
1066    /// services.add_singleton(UserService { name: "Alice".to_string() });
1067    /// services.decorate_with::<UserService, _>(LoggingDecorator);
1068    ///
1069    /// let provider = services.build();
1070    /// let user = provider.get_required::<UserService>(); // Logs: "Accessing user: Alice"
1071    /// # Ok(())
1072    /// # }
1073    /// ```
1074    pub fn decorate_with<T, D>(&mut self, decorator: D) -> &mut Self
1075    where
1076        T: 'static + Send + Sync,
1077        D: crate::decoration::ServiceDecorator<T> + 'static,
1078    {
1079        use crate::decoration::DecorationWrapper;
1080
1081        let key = crate::key::key_of_type::<T>();
1082        
1083        if let Some(registration) = self.registry.get_mut(&key) {
1084            let old_ctor = registration.ctor.clone();
1085            let wrapper = Arc::new(DecorationWrapper::new(decorator));
1086            
1087            registration.ctor = Arc::new(move |resolver| {
1088                // Call original constructor
1089                let original = old_ctor(resolver)?;
1090                
1091                // Cast to the concrete type
1092                let typed = original.downcast::<T>()
1093                    .map_err(|_| crate::DiError::TypeMismatch(std::any::type_name::<T>()))?;
1094                
1095                // Apply decoration
1096                let decorated = wrapper.decorate(typed, resolver);
1097                
1098                // Wrap back in Arc<dyn Any>
1099                Ok(decorated as crate::registration::AnyArc)
1100            });
1101        }
1102        
1103        self
1104    }
1105
1106    /// Decorates a trait service type with a first-class decorator.
1107    ///
1108    /// Similar to `decorate_with` but works with trait objects for maximum flexibility.
1109    /// Essential for workflow engines that need to wrap trait implementations.
1110    ///
1111    /// # Examples
1112    ///
1113    /// ```
1114    /// use ferrous_di::{ServiceCollection, TraitDecorator, Resolver};
1115    /// use std::sync::Arc;
1116    ///
1117    /// trait Logger: Send + Sync {
1118    ///     fn log(&self, message: &str);
1119    /// }
1120    ///
1121    /// struct ConsoleLogger;
1122    /// impl Logger for ConsoleLogger {
1123    ///     fn log(&self, message: &str) {
1124    ///         println!("LOG: {}", message);
1125    ///     }
1126    /// }
1127    ///
1128    /// struct PrefixDecorator;
1129    ///
1130    /// impl TraitDecorator<dyn Logger> for PrefixDecorator {
1131    ///     fn decorate(&self, original: Arc<dyn Logger>, _resolver: &dyn ferrous_di::traits::ResolverCore) -> Arc<dyn Logger> {
1132    ///         struct PrefixLogger {
1133    ///             inner: Arc<dyn Logger>,
1134    ///         }
1135    ///         impl Logger for PrefixLogger {
1136    ///             fn log(&self, message: &str) {
1137    ///                 self.inner.log(&format!("[WORKFLOW] {}", message));
1138    ///             }
1139    ///         }
1140    ///         Arc::new(PrefixLogger { inner: original })
1141    ///     }
1142    /// }
1143    ///
1144    /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
1145    /// let mut services = ServiceCollection::new();
1146    /// services.add_singleton_trait::<dyn Logger>(Arc::new(ConsoleLogger));
1147    /// services.decorate_trait_with::<dyn Logger, _>(PrefixDecorator);
1148    ///
1149    /// let provider = services.build();
1150    /// let logger = provider.get_required_trait::<dyn Logger>();
1151    /// logger.log("Hello"); // Outputs: "[WORKFLOW] LOG: Hello"
1152    /// # Ok(())
1153    /// # }
1154    /// ```
1155    pub fn decorate_trait_with<T, D>(&mut self, decorator: D) -> &mut Self
1156    where
1157        T: ?Sized + 'static + Send + Sync,
1158        D: crate::decoration::TraitDecorator<T> + 'static,
1159    {
1160        use crate::decoration::TraitDecorationWrapper;
1161
1162        let trait_name = std::any::type_name::<T>();
1163        let wrapper = Arc::new(TraitDecorationWrapper::new(decorator));
1164        
1165        // Decorate single-binding registration if it exists
1166        let single_key = crate::Key::Trait(trait_name);
1167        if let Some(registration) = self.registry.get_mut(&single_key) {
1168            let old_ctor = registration.ctor.clone();
1169            let wrapper_clone = wrapper.clone();
1170            
1171            registration.ctor = Arc::new(move |resolver| {
1172                // Call original constructor
1173                let original = old_ctor(resolver)?;
1174                
1175                // Cast to the trait type and apply decorator
1176                let typed = original.downcast::<Arc<T>>()
1177                    .map_err(|_| crate::DiError::TypeMismatch(trait_name))?;
1178                let decorated = wrapper_clone.decorate((*typed).clone(), resolver);
1179                
1180                // Wrap back in Arc<dyn Any>
1181                Ok(Arc::new(decorated) as crate::registration::AnyArc)
1182            });
1183        }
1184        
1185        // Decorate multi-binding registrations if they exist
1186        if let Some(registrations) = self.registry.many.get_mut(trait_name) {
1187            for registration in registrations.iter_mut() {
1188                let old_ctor = registration.ctor.clone();
1189                let wrapper_clone = wrapper.clone();
1190                
1191                registration.ctor = Arc::new(move |resolver| {
1192                    // Call original constructor
1193                    let original = old_ctor(resolver)?;
1194                    
1195                    // Cast to the trait type and apply decorator
1196                    let typed = original.downcast::<Arc<T>>()
1197                        .map_err(|_| crate::DiError::TypeMismatch(trait_name))?;
1198                    let decorated = wrapper_clone.decorate((*typed).clone(), resolver);
1199                    
1200                    // Wrap back in Arc<dyn Any>
1201                    Ok(Arc::new(decorated) as crate::registration::AnyArc)
1202                });
1203            }
1204        }
1205        
1206        self
1207    }
1208    
1209    // ----- Pre-warm / Readiness -----
1210    
1211    /// Marks a concrete service type for pre-warming during startup.
1212    ///
1213    /// Pre-warmed services are resolved during the `ServiceProvider::ready()` call,
1214    /// eliminating cold-start penalties during agent execution. This is particularly
1215    /// useful for expensive-to-initialize services like ML models, database
1216    /// connections, and authentication tokens.
1217    ///
1218    /// Services that implement `ReadyCheck` will also have their readiness
1219    /// verified during the pre-warm phase.
1220    ///
1221    /// # Examples
1222    ///
1223    /// ```
1224    /// use ferrous_di::{ServiceCollection, ReadyCheck};
1225    /// use async_trait::async_trait;
1226    ///
1227    /// struct DatabaseService {
1228    ///     connection: String,
1229    /// }
1230    ///
1231    /// #[async_trait]
1232    /// impl ReadyCheck for DatabaseService {
1233    ///     async fn ready(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
1234    ///         // Test database connection
1235    ///         Ok(())
1236    ///     }
1237    /// }
1238    ///
1239    /// let mut services = ServiceCollection::new();
1240    /// services.add_singleton(DatabaseService {
1241    ///     connection: "postgres://localhost".to_string()
1242    /// });
1243    /// services.prewarm::<DatabaseService>(); // Pre-warm during startup
1244    ///
1245    /// // Later during startup:
1246    /// let provider = services.build();
1247    /// // let report = provider.ready().await?; // Resolves and checks DatabaseService
1248    /// ```
1249    pub fn prewarm<T: 'static + Send + Sync>(&mut self) -> &mut Self {
1250        self.prewarm.add_type::<T>();
1251        self
1252    }
1253
1254    /// Marks a trait service type for pre-warming during startup.
1255    ///
1256    /// Pre-warmed trait services have all their implementations resolved
1257    /// during the `ServiceProvider::ready()` call.
1258    ///
1259    /// # Examples
1260    ///
1261    /// ```
1262    /// use ferrous_di::{ServiceCollection, ReadyCheck};
1263    /// use async_trait::async_trait;
1264    /// use std::sync::Arc;
1265    ///
1266    /// trait CacheService: Send + Sync {
1267    ///     fn get(&self, key: &str) -> Option<String>;
1268    /// }
1269    ///
1270    /// struct RedisCache;
1271    /// impl CacheService for RedisCache {
1272    ///     fn get(&self, key: &str) -> Option<String> {
1273    ///         // Redis implementation
1274    ///         None
1275    ///     }
1276    /// }
1277    ///
1278    /// #[async_trait]
1279    /// impl ReadyCheck for RedisCache {
1280    ///     async fn ready(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
1281    ///         // Test Redis connection
1282    ///         Ok(())
1283    ///     }
1284    /// }
1285    ///
1286    /// let mut services = ServiceCollection::new();
1287    /// services.add_singleton_trait::<dyn CacheService>(Arc::new(RedisCache));
1288    /// services.prewarm_trait::<dyn CacheService>(); // Pre-warm all cache implementations
1289    ///
1290    /// let provider = services.build();
1291    /// // let report = provider.ready().await?; // Resolves and checks all cache services
1292    /// ```
1293    pub fn prewarm_trait<T: ?Sized + 'static + Send + Sync>(&mut self) -> &mut Self {
1294        self.prewarm.add_trait::<T>();
1295        self
1296    }
1297    
1298    /// Builds the final service provider from this collection.
1299    ///
1300    /// This method consumes the `ServiceCollection` and creates a `ServiceProvider`
1301    /// that can resolve registered services. The service provider is thread-safe
1302    /// and can be used to create scoped contexts for request-scoped services.
1303    ///
1304    /// # Returns
1305    ///
1306    /// A `ServiceProvider` that can resolve all registered services according to
1307    /// their configured lifetimes.
1308    ///
1309    /// # Examples
1310    ///
1311    /// ```
1312    /// use ferrous_di::{ServiceCollection, Resolver};
1313    /// use std::sync::Arc;
1314    ///
1315    /// let mut collection = ServiceCollection::new();
1316    /// collection.add_singleton(42usize);
1317    /// collection.add_transient_factory::<String, _>(|_| "Hello".to_string());
1318    ///
1319    /// let provider = collection.build();
1320    /// let number = provider.get_required::<usize>();
1321    /// let text = provider.get_required::<String>();
1322    ///
1323    /// assert_eq!(*number, 42);
1324    /// assert_eq!(&*text, "Hello");
1325    /// ```
1326    pub fn build(mut self) -> ServiceProvider {
1327        // Finalize registry by assigning scoped slot indices
1328        self.registry.finalize();
1329        ServiceProvider::new_with_observers_and_capabilities(self.registry, self.observers, self.capabilities)
1330    }
1331
1332    /// Registers an async singleton service with a factory.
1333    ///
1334    /// Perfect for workflow engines where nodes/tools need async initialization
1335    /// (network handshakes, auth, model warm-up).
1336    ///
1337    /// # Examples
1338    ///
1339    /// ```
1340    /// use ferrous_di::{ServiceCollection, AsyncFactory};
1341    /// use async_trait::async_trait;
1342    /// use std::sync::Arc;
1343    ///
1344    /// struct DatabasePool {
1345    ///     connection_string: String,
1346    /// }
1347    ///
1348    /// struct AsyncDbPoolFactory;
1349    ///
1350    /// #[async_trait]
1351    /// impl AsyncFactory<DatabasePool> for AsyncDbPoolFactory {
1352    ///     async fn create(&self, _resolver: &dyn ferrous_di::Resolver) -> Arc<DatabasePool> {
1353    ///         // Simulate async database connection setup
1354    ///         Arc::new(DatabasePool {
1355    ///             connection_string: "postgres://localhost".to_string(),
1356    ///         })
1357    ///     }
1358    /// }
1359    ///
1360    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
1361    /// let mut services = ServiceCollection::new();
1362    /// services.add_singleton_async::<DatabasePool, _>(AsyncDbPoolFactory);
1363    /// # Ok(())
1364    /// # }
1365    /// ```
1366    #[cfg(feature = "async")]
1367    pub fn add_singleton_async<T, F>(&mut self, factory: F) -> &mut Self
1368    where
1369        T: Send + Sync + Clone + 'static,
1370        F: crate::async_factories::AsyncFactory<T> + 'static,
1371    {
1372        use crate::async_factories::AsyncFactoryWrapper;
1373        
1374        let wrapper = AsyncFactoryWrapper::new(factory);
1375        
1376        // Create a sync factory that executes the async factory in a blocking context
1377        let sync_factory = move |resolver: &ResolverContext| -> Arc<T> {
1378            // Try to get current tokio runtime handle
1379            if let Ok(_handle) = tokio::runtime::Handle::try_current() {
1380                // We're in an async context, but we can't block_on from within the runtime
1381                // Instead, use block_in_place to run the async task
1382                let future = wrapper.create(resolver);
1383                let result = tokio::task::block_in_place(|| {
1384                    // Create a new runtime for this blocking task
1385                    let rt = tokio::runtime::Builder::new_current_thread()
1386                        .enable_all()
1387                        .build()
1388                        .expect("Failed to create blocking runtime");
1389                    rt.block_on(future)
1390                });
1391                
1392                match result {
1393                    Ok(result) => result,
1394                    Err(e) => {
1395                        panic!("Async factory failed: {}", e);
1396                    }
1397                }
1398            } else {
1399                // No async runtime, create a new one for this operation
1400                let rt = tokio::runtime::Builder::new_multi_thread()
1401                    .enable_all()
1402                    .build()
1403                    .expect("Failed to create async runtime");
1404                match rt.block_on(wrapper.create(resolver)) {
1405                    Ok(result) => result,
1406                    Err(e) => {
1407                        panic!("Async factory failed: {}", e);
1408                    }
1409                }
1410            }
1411        };
1412        
1413        // Register as singleton with the sync factory that returns Arc<T>
1414        self.add_singleton_factory::<Arc<T>, _>(sync_factory);
1415        self
1416    }
1417
1418    /// Registers an async scoped service with a factory.
1419    ///
1420    /// Perfect for per-workflow or per-node async initialization in workflow engines.
1421    ///
1422    /// # Examples
1423    ///
1424    /// ```
1425    /// use ferrous_di::{ServiceCollection, async_factory};
1426    /// use std::sync::Arc;
1427    ///
1428    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
1429    /// let mut services = ServiceCollection::new();
1430    /// 
1431    /// services.add_scoped_async::<String, _>(async_factory!(|_resolver| async {
1432    ///     // Simulate async session initialization
1433    ///     Arc::new("session_initialized".to_string())
1434    /// }));
1435    /// # Ok(())
1436    /// # }
1437    /// ```
1438    #[cfg(feature = "async")]
1439    pub fn add_scoped_async<T, F>(&mut self, factory: F) -> &mut Self
1440    where
1441        T: Send + Sync + Clone + 'static,
1442        F: crate::async_factories::AsyncFactory<T> + 'static,
1443    {
1444        use crate::async_factories::AsyncFactoryWrapper;
1445        
1446        let wrapper = AsyncFactoryWrapper::new(factory);
1447        
1448        // Create a sync factory that executes the async factory in a blocking context
1449        let sync_factory = move |resolver: &ResolverContext| -> Arc<T> {
1450            // Try to get current tokio runtime handle
1451            if let Ok(_handle) = tokio::runtime::Handle::try_current() {
1452                // We're in an async context, but we can't block_on from within the runtime
1453                // Instead, use spawn_blocking to run the async task
1454                let future = wrapper.create(resolver);
1455                let result = tokio::task::block_in_place(|| {
1456                    // Create a new runtime for this blocking task
1457                    let rt = tokio::runtime::Builder::new_current_thread()
1458                        .enable_all()
1459                        .build()
1460                        .expect("Failed to create blocking runtime");
1461                    rt.block_on(future)
1462                });
1463                
1464                match result {
1465                    Ok(result) => result,
1466                    Err(e) => {
1467                        panic!("Async factory failed: {}", e);
1468                    }
1469                }
1470            } else {
1471                // No async runtime, create a new one for this operation
1472                let rt = tokio::runtime::Builder::new_multi_thread()
1473                    .enable_all()
1474                    .build()
1475                    .expect("Failed to create async runtime");
1476                match rt.block_on(wrapper.create(resolver)) {
1477                    Ok(result) => result,
1478                    Err(e) => {
1479                        panic!("Async factory failed: {}", e);
1480                    }
1481                }
1482            }
1483        };
1484        
1485        // Register as scoped with the sync factory that returns Arc<T>
1486        self.add_scoped_factory::<Arc<T>, _>(sync_factory);
1487        self
1488    }
1489}
1490
1491impl Default for ServiceCollection {
1492    fn default() -> Self {
1493        Self::new()
1494    }
1495}
1496