use crate::{request::Request, responder::Responder, response::Builder};
use async_trait::async_trait;
use std::future::Future;
pub type ControllerMethod<C> = (
Option<&'static str>,
&'static str,
&'static str,
Box<dyn ControllerHandler<C> + Send + Sync>,
);
pub trait Controller {
const BASE_PATH: &'static str;
fn method(&self) -> Vec<ControllerMethod<Self>>
where
Self: Sized;
}
#[async_trait]
pub trait ControllerHandler<C> {
async fn handle(&self, controller: &'static C, req: Request) -> Builder;
}
#[async_trait]
impl<C, F, Fut, R> ControllerHandler<C> for F
where
C: 'static + Sync,
R: Responder + 'static + Send,
Fut: Future<Output = R> + Send + 'static,
F: Fn(&'static C, Request) -> Fut + Sync,
{
#[inline]
async fn handle(&self, controller: &'static C, req: Request) -> Builder {
let builder = Builder::new();
self(controller, req).await.response(builder)
}
}
macro_rules! method {
($($(#[$m:meta])* $v:vis fn $n:ident = $method:expr;)+) => {
$(
$(#[$m])* $v fn $n<H>(self,path: &'static str,handler: H) -> Self
where
H: ControllerHandler<C> + Send + Sync + 'static,
{
self.add(path,$method,handler)
}
)+
};
}
#[derive(Default)]
pub struct ControllerBuilder<C: Controller> {
handlers: Vec<ControllerMethod<C>>,
}
impl<C: Controller> ControllerBuilder<C> {
#[inline]
pub fn new() -> Self {
Self {
handlers: Default::default(),
}
}
#[inline]
fn add<H>(mut self, path: &'static str, method: &'static str, handler: H) -> Self
where
H: ControllerHandler<C> + Send + Sync + 'static,
{
self.handlers.push((None, method, path, Box::new(handler)));
self
}
#[inline]
pub fn add_with_name<H>(
mut self,
handler_name: &'static str,
path: &'static str,
method: &'static str,
handler: H,
) -> Self
where
H: 'static + ControllerHandler<C> + Send + Sync,
{
self.handlers
.push((Some(handler_name), method, path, Box::new(handler)));
self
}
method![
#[inline]
pub fn get = "GET";
#[inline]
pub fn post = "POST";
#[inline]
pub fn options = "OPTIONS";
#[inline]
pub fn put = "PUT";
#[inline]
pub fn delete = "DELETE";
#[inline]
pub fn head = "HEAD";
#[inline]
pub fn trace = "TRACE";
#[inline]
pub fn connect = "CONNECT";
#[inline]
pub fn patch = "PATCH";
];
#[inline]
pub fn build(self) -> Vec<ControllerMethod<C>> {
self.handlers
}
}