#![doc = include_str!("../../DI.md")]
use crate::app::AppBuilder;
use crate::config::ConfigRegistry;
use crate::error::Result;
use crate::plugin::ComponentRegistry;
pub use summer_macros::Service;
pub trait Service: Clone + Sized + 'static {
fn build<R>(registry: &R) -> Result<Self>
where
R: ComponentRegistry + ConfigRegistry;
}
pub trait ServiceRegistrar: Send + Sync + 'static {
fn install_service(&self, app: &mut AppBuilder) -> Result<()>;
}
inventory::collect!(&'static dyn ServiceRegistrar);
#[macro_export]
macro_rules! submit_service {
($ty:ident) => {
::summer::submit_inventory! {
&$ty as &dyn ::summer::plugin::service::ServiceRegistrar
}
};
}
pub fn auto_inject_service(app: &mut AppBuilder) -> Result<()> {
let registrars: Vec<&'static &dyn ServiceRegistrar> =
inventory::iter::<&dyn ServiceRegistrar>().collect();
let total = registrars.len();
let mut pending: Vec<&'static &dyn ServiceRegistrar> = registrars;
let mut installed = 0;
while !pending.is_empty() {
let mut next_pending = Vec::new();
let mut progress_made = false;
for registrar in pending {
match registrar.install_service(app) {
Ok(()) => {
installed += 1;
progress_made = true;
}
Err(_) => {
next_pending.push(registrar);
}
}
}
if !progress_made && !next_pending.is_empty() {
if let Some(first) = next_pending.first() {
return first.install_service(app);
}
}
pending = next_pending;
}
log::debug!("Installed {installed}/{total} services");
Ok(())
}