use std::{
any::{Any, TypeId},
collections::{HashMap, HashSet},
future::Future,
pin::Pin,
sync::{Arc, Mutex},
};
pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
pub trait Injectable: Send + Sync + 'static {
fn create(container: &Container) -> BoxFuture<'_, crate::Result<Self>>
where
Self: Sized;
fn dependencies() -> Vec<crate::ProviderDependency>
where
Self: Sized;
fn on_module_init(&self) -> BoxFuture<'_, crate::Result<()>> {
Box::pin(async { Ok(()) })
}
fn on_bootstrap(&self) -> BoxFuture<'_, crate::Result<()>> {
Box::pin(async { Ok(()) })
}
fn on_shutdown(&self) -> BoxFuture<'_, crate::Result<()>> {
Box::pin(async { Ok(()) })
}
}
pub struct Container {
services: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
pub(crate) pending_overrides: HashMap<TypeId, crate::ProviderDef>,
pub(crate) applied_overrides: HashSet<TypeId>,
declared_provider_types: HashSet<TypeId>,
pub(crate) initialized_providers: Arc<Mutex<Vec<TypeId>>>,
pub(crate) bootstrapped_providers: Arc<Mutex<HashSet<TypeId>>>,
dependency_scope: Option<Arc<DependencyScope>>,
}
struct DependencyScope {
provider_type_name: &'static str,
allowed_type_ids: HashSet<TypeId>,
}
impl Clone for Container {
fn clone(&self) -> Self {
Self {
services: self.services.clone(),
pending_overrides: HashMap::new(),
applied_overrides: self.applied_overrides.clone(),
declared_provider_types: self.declared_provider_types.clone(),
initialized_providers: self.initialized_providers.clone(),
bootstrapped_providers: self.bootstrapped_providers.clone(),
dependency_scope: self.dependency_scope.clone(),
}
}
}
impl Container {
pub fn new() -> Self {
crate::logging::init_logging();
let mut services: HashMap<TypeId, Arc<dyn Any + Send + Sync>> = HashMap::new();
services.insert(
TypeId::of::<crate::Logger>(),
Arc::new(crate::Logger::new("Application")),
);
Self {
services,
pending_overrides: HashMap::new(),
applied_overrides: HashSet::new(),
declared_provider_types: HashSet::new(),
initialized_providers: Arc::new(Mutex::new(Vec::new())),
bootstrapped_providers: Arc::new(Mutex::new(HashSet::new())),
dependency_scope: None,
}
}
pub fn register_instance<T: Send + Sync + 'static>(&mut self, value: T) {
self.services.insert(TypeId::of::<T>(), Arc::new(value));
}
pub async fn register<T: Injectable>(&mut self) -> crate::Result<()> {
let instance = T::create(self).await?;
let instance = Arc::new(instance);
instance.on_module_init().await.map_err(|err| {
crate::exception::startup_error(format!(
"on_module_init failed for {}: {}: {}",
std::any::type_name::<T>(),
err.error,
err.message
))
})?;
self.services.insert(TypeId::of::<T>(), instance);
Ok(())
}
pub(crate) fn register_erased(&mut self, type_id: TypeId, value: Arc<dyn Any + Send + Sync>) {
self.services.insert(type_id, value);
}
pub(crate) fn resolve_erased(&self, type_id: TypeId) -> Option<Arc<dyn Any + Send + Sync>> {
self.services.get(&type_id).cloned()
}
pub(crate) fn contains_type_id(&self, type_id: TypeId) -> bool {
self.services.contains_key(&type_id)
}
pub(crate) fn take_pending_override(&mut self, type_id: TypeId) -> Option<crate::ProviderDef> {
self.pending_overrides.remove(&type_id)
}
pub(crate) fn mark_override_applied(&mut self, type_id: TypeId) {
self.applied_overrides.insert(type_id);
}
pub(crate) fn was_overridden(&self, type_id: TypeId) -> bool {
self.applied_overrides.contains(&type_id)
}
pub(crate) fn begin_provider_bootstrap(&self, type_id: TypeId) -> bool {
self.bootstrapped_providers
.lock()
.expect("provider lifecycle lock poisoned")
.insert(type_id)
}
pub(crate) fn mark_provider_declared(&mut self, type_id: TypeId) {
self.declared_provider_types.insert(type_id);
}
pub(crate) fn seed_overrides(&mut self, overrides: crate::ProviderOverrides) {
self.pending_overrides = overrides.into_inner();
}
pub(crate) fn has_pending_override(&self, type_id: TypeId) -> bool {
self.pending_overrides.contains_key(&type_id)
}
pub(crate) fn pending_override(&self, type_id: TypeId) -> Option<&crate::ProviderDef> {
self.pending_overrides.get(&type_id)
}
pub(crate) fn record_initialized_provider(&self, type_id: TypeId) {
self.initialized_providers
.lock()
.expect("provider lifecycle lock poisoned")
.push(type_id);
}
pub(crate) fn take_initialized_providers(&self) -> Vec<TypeId> {
std::mem::take(
&mut *self
.initialized_providers
.lock()
.expect("provider lifecycle lock poisoned"),
)
}
pub(crate) fn initialized_provider_types(&self) -> Vec<TypeId> {
self.initialized_providers
.lock()
.expect("provider lifecycle lock poisoned")
.clone()
}
pub(crate) fn scoped_for_provider(
&self,
provider_type_name: &'static str,
dependencies: &[crate::ProviderDependency],
) -> Self {
let mut scoped = self.clone();
scoped.dependency_scope = Some(Arc::new(DependencyScope {
provider_type_name,
allowed_type_ids: dependencies
.iter()
.map(|dependency| dependency.type_id())
.collect(),
}));
scoped
}
pub(crate) fn assert_no_unused_overrides(&self) -> crate::Result<()> {
if self.pending_overrides.is_empty() {
return Ok(());
}
let mut names: Vec<&'static str> = self
.pending_overrides
.values()
.map(|provider| provider.type_name())
.collect();
names.sort_unstable();
Err(crate::exception::startup_error(format!(
"provider override was never applied: {}; is it registered in the module tree?",
names.join(", ")
)))
}
pub fn resolve<T: Send + Sync + 'static>(&self) -> crate::Result<Arc<T>> {
let type_id = TypeId::of::<T>();
if let Some(scope) = &self.dependency_scope
&& type_id != TypeId::of::<crate::Logger>()
&& !scope.allowed_type_ids.contains(&type_id)
{
return Err(crate::exception::startup_error(format!(
"{} resolved {} without declaring it in dependencies()",
scope.provider_type_name,
std::any::type_name::<T>()
)));
}
let value = self.services.get(&type_id).ok_or_else(|| {
crate::exception::startup_error(format!(
"no provider registered for {}",
std::any::type_name::<T>()
))
})?;
value.clone().downcast::<T>().map_err(|_| {
crate::exception::startup_error(format!(
"type mismatch resolving {}",
std::any::type_name::<T>()
))
})
}
pub fn resolve_logger(&self, context: impl Into<String>) -> Arc<crate::Logger> {
Arc::new(crate::Logger::new(context))
}
}
impl Default for Container {
fn default() -> Self {
Self::new()
}
}