elif_core/providers/
registry.rs1use crate::container::ContainerBuilder;
2use crate::providers::{ServiceProvider, ProviderError, ProviderMetadata};
3use std::collections::HashMap;
4
5pub 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 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 pub fn provider_count(&self) -> usize {
34 self.providers.len()
35 }
36
37 pub fn get_metadata(&self, name: &str) -> Option<&ProviderMetadata> {
39 self.metadata_cache.get(name)
40 }
41
42 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 self.registration_order = self.topological_sort(&name_to_index, false)?;
52
53 self.boot_order = self.topological_sort(&name_to_index, true)?;
55
56 Ok(())
57 }
58
59 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 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 #[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 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 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 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}