Skip to main content

caelix_core/
container.rs

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