elif_core/providers/
registry.rs

1use crate::container::ContainerBuilder;
2use crate::providers::{ServiceProvider, ProviderError, ProviderMetadata};
3use std::collections::HashMap;
4
5/// Provider registry manages service providers and their lifecycle
6pub struct ProviderRegistry {
7    providers: Vec<Box<dyn ServiceProvider>>,
8    registration_order: Vec<usize>,
9    boot_order: Vec<usize>,
10    metadata_cache: HashMap<String, ProviderMetadata>,
11}
12
13impl ProviderRegistry {
14    pub fn new() -> Self {
15        Self {
16            providers: Vec::new(),
17            registration_order: Vec::new(),
18            boot_order: Vec::new(),
19            metadata_cache: HashMap::new(),
20        }
21    }
22    
23    /// Register a service provider
24    pub fn register<P: ServiceProvider + 'static>(&mut self, provider: P) {
25        let metadata = ProviderMetadata::from_provider(&provider);
26        let name = metadata.name.clone();
27        
28        self.providers.push(Box::new(provider));
29        self.metadata_cache.insert(name, metadata);
30    }
31    
32    /// Get the number of registered providers
33    pub fn provider_count(&self) -> usize {
34        self.providers.len()
35    }
36    
37    /// Get provider metadata by name
38    pub fn get_metadata(&self, name: &str) -> Option<&ProviderMetadata> {
39        self.metadata_cache.get(name)
40    }
41    
42    /// Resolve provider dependencies and determine execution order
43    pub fn resolve_dependencies(&mut self) -> Result<(), ProviderError> {
44        let name_to_index: HashMap<String, usize> = self.providers
45            .iter()
46            .enumerate()
47            .map(|(i, p)| (p.name().to_string(), i))
48            .collect();
49        
50        // Resolve registration order (topological sort)
51        self.registration_order = self.topological_sort(&name_to_index, false)?;
52        
53        // Resolve boot order (separate sort considering defer_boot)
54        self.boot_order = self.topological_sort(&name_to_index, true)?;
55        
56        Ok(())
57    }
58    
59    /// Perform topological sort considering dependencies
60    fn topological_sort(&self, name_to_index: &HashMap<String, usize>, consider_defer: bool) -> Result<Vec<usize>, ProviderError> {
61        let provider_count = self.providers.len();
62        let mut visited = vec![false; provider_count];
63        let mut temp_mark = vec![false; provider_count];
64        let mut result = Vec::new();
65        
66        // Visit all providers
67        for i in 0..provider_count {
68            if !visited[i] {
69                self.visit_provider(i, name_to_index, &mut visited, &mut temp_mark, &mut result, consider_defer)?;
70            }
71        }
72        
73        Ok(result)
74    }
75    
76    /// Visit provider for dependency resolution
77    #[allow(clippy::only_used_in_recursion)]
78    fn visit_provider(
79        &self,
80        index: usize,
81        name_to_index: &HashMap<String, usize>,
82        visited: &mut Vec<bool>,
83        temp_mark: &mut Vec<bool>,
84        result: &mut Vec<usize>,
85        consider_defer: bool,
86    ) -> Result<(), ProviderError> {
87        if temp_mark[index] {
88            return Err(ProviderError::CircularDependency {
89                provider: self.providers[index].name().to_string(),
90            });
91        }
92        
93        if visited[index] {
94            return Ok(());
95        }
96        
97        temp_mark[index] = true;
98        
99        // Visit all dependencies first
100        let dependencies = self.providers[index].dependencies();
101        for dep_name in dependencies {
102            if let Some(&dep_index) = name_to_index.get(dep_name) {
103                self.visit_provider(dep_index, name_to_index, visited, temp_mark, result, consider_defer)?;
104            } else {
105                return Err(ProviderError::MissingDependency {
106                    provider: self.providers[index].name().to_string(),
107                    dependency: dep_name.to_string(),
108                });
109            }
110        }
111        
112        temp_mark[index] = false;
113        visited[index] = true;
114        result.push(index);
115        
116        Ok(())
117    }
118    
119    /// Register all providers with the container builder
120    pub fn register_all(&self, mut builder: ContainerBuilder) -> Result<ContainerBuilder, ProviderError> {
121        for &index in &self.registration_order {
122            let provider = &self.providers[index];
123            tracing::info!("Registering provider: {}", provider.name());
124            builder = provider.register(builder)?;
125        }
126        Ok(builder)
127    }
128    
129    /// Boot all providers after container is built
130    pub fn boot_all(&self, container: &crate::container::Container) -> Result<(), ProviderError> {
131        for &index in &self.boot_order {
132            let provider = &self.providers[index];
133            tracing::info!("Booting provider: {}", provider.name());
134            provider.boot(container).map_err(|e| {
135                ProviderError::BootFailed {
136                    message: format!("Failed to boot provider '{}': {}", provider.name(), e),
137                }
138            })?;
139        }
140        Ok(())
141    }
142}
143
144impl Default for ProviderRegistry {
145    fn default() -> Self {
146        Self::new()
147    }
148}