use std::any::{Any, TypeId};
use std::collections::HashMap;
use eyre::Result;
use once_cell::sync::OnceCell;
pub use database::Database;
pub use metrics::Metrics;
pub use redis::Redis;
use crate::contracts::{Application, Service};
mod database;
mod metrics;
mod redis;
pub struct ServiceProvider(HashMap<TypeId, Box<dyn Any + Send + Sync>>);
impl Default for ServiceProvider {
fn default() -> Self {
Self::new()
}
}
impl ServiceProvider {
pub fn new() -> Self {
Self(HashMap::new())
}
pub fn register<A: Application + ?Sized, T: Service>(&mut self) {
self.0
.insert(TypeId::of::<T>(), Box::new(T::register::<A>()));
}
pub fn boot<A: Application + ?Sized, T: Service>(&self) -> Result<()> {
T::boot::<A>()?;
Ok(())
}
pub fn get<T: Service>(&self) -> Option<&T> {
self.0
.get(&TypeId::of::<T>())
.and_then(|boxed| boxed.downcast_ref::<T>())
}
pub fn into_static(self) -> &'static ServiceProvider {
SERVICES.get_or_init(|| self)
}
}
static SERVICES: OnceCell<ServiceProvider> = OnceCell::new();
pub fn service() -> &'static ServiceProvider {
SERVICES.get().expect("ServiceProvider not initialized")
}