use std::any::type_name_of_val;
use std::fmt::{Debug, Formatter};
use crate::body::ResponseBody;
use crate::fn_trait::FnTrait;
use crate::responder::Responder;
use crate::{OptionReqBody, RequestContext};
use async_trait::async_trait;
use http::Response;
use crate::extract::FromRequest;
use std::marker::PhantomData;
pub mod handler_decorator;
pub mod handler_decorator_factory;
#[async_trait]
pub trait RequestHandler: Send + Sync {
async fn invoke<'server, 'req>(&self, req: &mut RequestContext<'server, 'req>, req_body: OptionReqBody) -> Response<ResponseBody>;
}
impl Debug for dyn RequestHandler {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "dyn request_handler: {}", type_name_of_val(self))
}
}
#[async_trait]
impl<T> RequestHandler for Box<T>
where
T: RequestHandler,
{
async fn invoke<'server, 'req>(&self, req: &mut RequestContext<'server, 'req>, req_body: OptionReqBody) -> Response<ResponseBody> {
(**self).invoke(req, req_body).await
}
}
#[async_trait]
impl RequestHandler for Box<dyn RequestHandler> {
async fn invoke<'server, 'req>(&self, req: &mut RequestContext<'server, 'req>, req_body: OptionReqBody) -> Response<ResponseBody> {
(**self).invoke(req, req_body).await
}
}
#[async_trait]
impl RequestHandler for &dyn RequestHandler {
async fn invoke<'server, 'req>(&self, req: &mut RequestContext<'server, 'req>, req_body: OptionReqBody) -> Response<ResponseBody> {
(**self).invoke(req, req_body).await
}
}
pub struct FnHandler<F, Args> {
f: F,
_phantom: PhantomData<fn(Args)>,
}
impl<F, Args> Debug for FnHandler<F, Args> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "fn_handler: {}", type_name_of_val(self))
}
}
impl<F, Args> FnHandler<F, Args>
where
F: FnTrait<Args>,
{
fn new(f: F) -> Self {
Self { f, _phantom: PhantomData }
}
}
pub fn handler_fn<F, Args>(f: F) -> FnHandler<F, Args>
where
F: FnTrait<Args>,
{
FnHandler::new(f)
}
#[async_trait]
impl<F, Args> RequestHandler for FnHandler<F, Args>
where
Args: FromRequest,
for<'r> F: FnTrait<Args::Output<'r>>,
for<'r> <F as FnTrait<Args::Output<'r>>>::Output: Responder,
{
async fn invoke<'server, 'req>(&self, req: &mut RequestContext<'server, 'req>, req_body: OptionReqBody) -> Response<ResponseBody> {
let args = match Args::from_request(req, req_body.clone()).await {
Ok(args) => args,
Err(responder) => return responder.response_to(req),
};
let responder = self.f.call(args).await;
responder.response_to(req)
}
}
#[cfg(test)]
mod test {
use crate::fn_trait::FnTrait;
use crate::handler::{FnHandler, RequestHandler};
use http::Method;
fn assert_is_fn_handler<H: FnTrait<Args>, Args>(_handler: &FnHandler<H, Args>) {
}
fn assert_is_handler<T: RequestHandler>(_handler: &T) {
}
#[test]
fn assert_fn_is_http_handler_1() {
async fn get(_header: Method) {}
let http_handler = FnHandler::new(get);
assert_is_fn_handler(&http_handler);
assert_is_handler(&http_handler);
}
#[test]
fn assert_fn_is_http_handler_2() {
async fn get(_header: &Method, _str: String) {}
let http_handler = FnHandler::new(get);
assert_is_fn_handler(&http_handler);
assert_is_handler(&http_handler);
}
}