use std::future::Future;
use anyhow::Result;
use axum::Router;
pub(crate) type HeapedController<S> = Box<dyn Controller<S>>;
pub(crate) type ControllerList<S> = Vec<HeapedController<S>>;
pub trait ControllerInitialization<S>
where
S: Clone + Send + Sync + 'static,
{
fn new() -> impl Future<Output = Result<Box<Self>>> where Self: Sized;
}
pub trait Controller<S>: ControllerInitialization<S>
where
S: Clone + Send + Sync + 'static,
{
fn register(&self, router: Router<S>) -> Router<S>;
}
pub(crate) trait ApplyControllerOnRouter<S>
where
S: Clone + Send + Sync + 'static,
{
fn use_controller(self, controller: &dyn Controller<S>) -> Router<S>;
fn use_controllers(self, controllers: ControllerList<S>) -> Router<S>;
}
impl<S> ApplyControllerOnRouter<S> for Router<S>
where
S: Clone + Send + Sync + 'static,
{
fn use_controller(self, controller: &dyn Controller<S>) -> Router<S>
{
controller.register(self)
}
fn use_controllers(self, controllers: ControllerList<S>) -> Router<S> {
controllers.into_iter().fold(self, |router, controller| {
router.use_controller(&*controller)
})
}
}
#[macro_export]
macro_rules! controllers {
($($controller:ty),* $(,)?) => {{
use adjust::controller::Controller;
let mut vec: Vec<Box<dyn adjust::controller::Controller<AppState>>> = Vec::new();
$(
match <$controller>::new().await {
Ok(controller) => {
log::debug!("{} successfully attached to Service", stringify!($controller));
vec.push(controller);
},
Err(e) => log::error!("{} threw an error and will not be attached to Service: {e}", stringify!($controller))
}
)*
vec
}};
}