Skip to main content

caelix_core/
container.rs

1use std::{
2    any::{Any, TypeId},
3    collections::{HashMap, HashSet},
4    future::Future,
5    pin::Pin,
6    sync::{Arc, Mutex},
7};
8
9pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
10
11pub trait Injectable: Send + Sync + 'static {
12    fn create(container: &Container) -> BoxFuture<'_, crate::Result<Self>>
13    where
14        Self: Sized;
15
16    /// Dependencies resolved while constructing this provider.
17    ///
18    /// `#[injectable]` supplies this automatically. Handwritten implementations
19    /// must return `provider_dependencies![...]`; Caelix rejects construction-time
20    /// resolution of a provider that is absent from this declaration.
21    fn dependencies() -> Vec<crate::ProviderDependency>
22    where
23        Self: Sized;
24
25    fn on_module_init(&self) -> BoxFuture<'_, crate::Result<()>> {
26        Box::pin(async { Ok(()) })
27    }
28
29    fn on_bootstrap(&self) -> BoxFuture<'_, crate::Result<()>> {
30        Box::pin(async { Ok(()) })
31    }
32
33    fn on_shutdown(&self) -> BoxFuture<'_, crate::Result<()>> {
34        Box::pin(async { Ok(()) })
35    }
36}
37
38pub struct Container {
39    services: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
40    /// Pending provider overrides consumed while registering the module tree.
41    pub(crate) pending_overrides: HashMap<TypeId, crate::ProviderDef>,
42    /// TypeIds that were satisfied by an override (skip declared lifecycle hooks).
43    pub(crate) applied_overrides: HashSet<TypeId>,
44    declared_provider_types: HashSet<TypeId>,
45    /// Successful production initializations, in startup order.
46    pub(crate) initialized_providers: Arc<Mutex<Vec<TypeId>>>,
47    pub(crate) bootstrapped_providers: Arc<Mutex<HashSet<TypeId>>>,
48    dependency_scope: Option<Arc<DependencyScope>>,
49}
50
51struct DependencyScope {
52    provider_type_name: &'static str,
53    allowed_type_ids: HashSet<TypeId>,
54}
55
56impl Clone for Container {
57    fn clone(&self) -> Self {
58        Self {
59            services: self.services.clone(),
60            // Overrides are build-time only; clones used by factories do not need them.
61            pending_overrides: HashMap::new(),
62            applied_overrides: self.applied_overrides.clone(),
63            declared_provider_types: self.declared_provider_types.clone(),
64            initialized_providers: self.initialized_providers.clone(),
65            bootstrapped_providers: self.bootstrapped_providers.clone(),
66            dependency_scope: self.dependency_scope.clone(),
67        }
68    }
69}
70
71impl Container {
72    pub fn new() -> Self {
73        crate::logging::init_logging();
74
75        let mut services: HashMap<TypeId, Arc<dyn Any + Send + Sync>> = HashMap::new();
76        services.insert(
77            TypeId::of::<crate::Logger>(),
78            Arc::new(crate::Logger::new("Application")),
79        );
80
81        Self {
82            services,
83            pending_overrides: HashMap::new(),
84            applied_overrides: HashSet::new(),
85            declared_provider_types: HashSet::new(),
86            initialized_providers: Arc::new(Mutex::new(Vec::new())),
87            bootstrapped_providers: Arc::new(Mutex::new(HashSet::new())),
88            dependency_scope: None,
89        }
90    }
91
92    pub fn register_instance<T: Send + Sync + 'static>(&mut self, value: T) {
93        self.services.insert(TypeId::of::<T>(), Arc::new(value));
94    }
95
96    pub async fn register<T: Injectable>(&mut self) -> crate::Result<()> {
97        let instance = T::create(self).await?;
98        let instance = Arc::new(instance);
99        instance.on_module_init().await.map_err(|err| {
100            crate::exception::startup_error(format!(
101                "on_module_init failed for {}: {}: {}",
102                std::any::type_name::<T>(),
103                err.error,
104                err.message
105            ))
106        })?;
107        self.services.insert(TypeId::of::<T>(), instance);
108        Ok(())
109    }
110
111    pub(crate) fn register_erased(&mut self, type_id: TypeId, value: Arc<dyn Any + Send + Sync>) {
112        self.services.insert(type_id, value);
113    }
114
115    pub(crate) fn resolve_erased(&self, type_id: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
116        self.services.get(&type_id).cloned()
117    }
118
119    pub(crate) fn contains_type_id(&self, type_id: TypeId) -> bool {
120        self.services.contains_key(&type_id)
121    }
122
123    pub(crate) fn take_pending_override(&mut self, type_id: TypeId) -> Option<crate::ProviderDef> {
124        self.pending_overrides.remove(&type_id)
125    }
126
127    pub(crate) fn mark_override_applied(&mut self, type_id: TypeId) {
128        self.applied_overrides.insert(type_id);
129    }
130
131    pub(crate) fn was_overridden(&self, type_id: TypeId) -> bool {
132        self.applied_overrides.contains(&type_id)
133    }
134
135    pub(crate) fn begin_provider_bootstrap(&self, type_id: TypeId) -> bool {
136        self.bootstrapped_providers
137            .lock()
138            .expect("provider lifecycle lock poisoned")
139            .insert(type_id)
140    }
141
142    pub(crate) fn mark_provider_declared(&mut self, type_id: TypeId) {
143        self.declared_provider_types.insert(type_id);
144    }
145
146    pub(crate) fn seed_overrides(&mut self, overrides: crate::ProviderOverrides) {
147        self.pending_overrides = overrides.into_inner();
148    }
149
150    pub(crate) fn has_pending_override(&self, type_id: TypeId) -> bool {
151        self.pending_overrides.contains_key(&type_id)
152    }
153
154    pub(crate) fn pending_override(&self, type_id: TypeId) -> Option<&crate::ProviderDef> {
155        self.pending_overrides.get(&type_id)
156    }
157
158    pub(crate) fn record_initialized_provider(&self, type_id: TypeId) {
159        self.initialized_providers
160            .lock()
161            .expect("provider lifecycle lock poisoned")
162            .push(type_id);
163    }
164
165    pub(crate) fn take_initialized_providers(&self) -> Vec<TypeId> {
166        std::mem::take(
167            &mut *self
168                .initialized_providers
169                .lock()
170                .expect("provider lifecycle lock poisoned"),
171        )
172    }
173
174    pub(crate) fn initialized_provider_types(&self) -> Vec<TypeId> {
175        self.initialized_providers
176            .lock()
177            .expect("provider lifecycle lock poisoned")
178            .clone()
179    }
180
181    pub(crate) fn scoped_for_provider(
182        &self,
183        provider_type_name: &'static str,
184        dependencies: &[crate::ProviderDependency],
185    ) -> Self {
186        let mut scoped = self.clone();
187        scoped.dependency_scope = Some(Arc::new(DependencyScope {
188            provider_type_name,
189            allowed_type_ids: dependencies
190                .iter()
191                .map(|dependency| dependency.type_id())
192                .collect(),
193        }));
194        scoped
195    }
196
197    pub(crate) fn assert_no_unused_overrides(&self) -> crate::Result<()> {
198        if self.pending_overrides.is_empty() {
199            return Ok(());
200        }
201
202        let mut names: Vec<&'static str> = self
203            .pending_overrides
204            .values()
205            .map(|provider| provider.type_name())
206            .collect();
207        names.sort_unstable();
208
209        Err(crate::exception::startup_error(format!(
210            "provider override was never applied: {}; is it registered in the module tree?",
211            names.join(", ")
212        )))
213    }
214
215    pub fn resolve<T: Send + Sync + 'static>(&self) -> crate::Result<Arc<T>> {
216        let type_id = TypeId::of::<T>();
217        if let Some(scope) = &self.dependency_scope
218            && type_id != TypeId::of::<crate::Logger>()
219            && !scope.allowed_type_ids.contains(&type_id)
220        {
221            return Err(crate::exception::startup_error(format!(
222                "{} resolved {} without declaring it in dependencies()",
223                scope.provider_type_name,
224                std::any::type_name::<T>()
225            )));
226        }
227
228        let value = self.services.get(&type_id).ok_or_else(|| {
229            crate::exception::startup_error(format!(
230                "no provider registered for {}",
231                std::any::type_name::<T>()
232            ))
233        })?;
234
235        value.clone().downcast::<T>().map_err(|_| {
236            crate::exception::startup_error(format!(
237                "type mismatch resolving {}",
238                std::any::type_name::<T>()
239            ))
240        })
241    }
242
243    pub fn resolve_logger(&self, context: impl Into<String>) -> Arc<crate::Logger> {
244        Arc::new(crate::Logger::new(context))
245    }
246}
247
248impl Default for Container {
249    fn default() -> Self {
250        Self::new()
251    }
252}