sinan 0.1.0

A Boilerplate for Rapid Axum Web Service Deployment.
Documentation
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")
}