#![allow(clippy::type_complexity)]
use crate::{ComponentRegistry, DependencyInjectionError as DIError, ProviderRegistry, State};
use std::{any::TypeId, collections::HashSet, sync::Arc};
pub struct DependencyContainer {
providers: ProviderRegistry,
components: ComponentRegistry,
}
impl DependencyContainer {
pub fn new() -> Self {
Self {
providers: ProviderRegistry::new(),
components: ComponentRegistry::new(),
}
}
pub fn provider_registry(&self) -> &ProviderRegistry {
&self.providers
}
pub fn component_registry(&self) -> &ComponentRegistry {
&self.components
}
pub fn build_all(&self, state: &State) -> Result<(), DIError> {
let mut built = HashSet::new();
let mut visiting = HashSet::new();
let providers = &self.providers.get_providers();
for (type_id, instance) in providers.read().iter() {
state.insert_instance(*type_id, Arc::clone(instance));
built.insert(*type_id);
}
for type_id in self.components.get_dependency_graph().read().keys() {
self.build_recursive(type_id, state, &mut built, &mut visiting)?;
}
Ok(())
}
fn build_recursive(
&self,
type_id: &TypeId,
state: &State,
built: &mut HashSet<TypeId>,
visiting: &mut HashSet<TypeId>,
) -> Result<(), DIError> {
if built.contains(type_id) {
return Ok(());
}
if visiting.contains(type_id) {
return Err(DIError::CircularDependency);
}
visiting.insert(*type_id);
let dependency_graph = &self.components.get_dependency_graph();
if let Some(deps) = dependency_graph.read().get(type_id) {
for dep_id in deps {
self.build_recursive(dep_id, state, built, visiting)?;
}
}
visiting.remove(type_id);
if let Some(builder) = &self.components.get_builders().read().get(type_id) {
state.insert_instance(*type_id, builder(state)?);
built.insert(*type_id);
}
Ok(())
}
}
impl Default for DependencyContainer {
fn default() -> Self {
Self::new()
}
}