use crate::call::Call;
use crate::response::{IntoResponse, Response};
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
pub type HandlerFuture = Pin<Box<dyn Future<Output = Response> + Send + 'static>>;
pub trait Handler: Send + Sync + 'static {
fn handle(&self, call: Call) -> HandlerFuture;
}
use crate::extract::{FromCall, FromCallParts};
pub trait HandlerFn<Marker>: Clone + Send + Sync + 'static {
fn call(self, call: Call) -> HandlerFuture;
}
macro_rules! impl_handler {
($($P:ident),*) => {
#[allow(non_snake_case, unused_mut, unused_variables)]
impl<F, Fut, R, $($P,)* L> HandlerFn<($($P,)* L,)> for F
where
F: Fn($($P,)* L) -> Fut + Clone + Send + Sync + 'static,
Fut: std::future::Future<Output = R> + Send + 'static,
R: IntoResponse + 'static,
$($P: FromCallParts + 'static,)*
L: FromCall + 'static,
{
fn call(self, call: Call) -> HandlerFuture {
let f = self;
Box::pin(async move {
let mut call = call;
$(
let $P = match <$P as FromCallParts>::from_call_parts(&mut call).await {
Ok(v) => v,
Err(e) => return e.into_response(),
};
)*
let last = match <L as FromCall>::from_call(call).await {
Ok(v) => v,
Err(e) => return e.into_response(),
};
f($($P,)* last).await.into_response()
})
}
}
};
}
impl<F, Fut, R> HandlerFn<()> for F
where
F: Fn() -> Fut + Clone + Send + Sync + 'static,
Fut: std::future::Future<Output = R> + Send + 'static,
R: IntoResponse + 'static,
{
fn call(self, _call: Call) -> HandlerFuture {
let f = self;
Box::pin(async move { f().await.into_response() })
}
}
impl_handler!();
impl_handler!(P1);
impl_handler!(P1, P2);
impl_handler!(P1, P2, P3);
impl_handler!(P1, P2, P3, P4);
impl_handler!(P1, P2, P3, P4, P5);
impl_handler!(P1, P2, P3, P4, P5, P6);
impl_handler!(P1, P2, P3, P4, P5, P6, P7);
impl_handler!(P1, P2, P3, P4, P5, P6, P7, P8);
pub type BoxHandler = Arc<dyn Handler>;
pub struct HandlerFnAdapter<Marker, H> {
handler: H,
_marker: std::marker::PhantomData<fn() -> Marker>,
}
impl<Marker, H> HandlerFnAdapter<Marker, H>
where
H: HandlerFn<Marker>,
{
fn new(handler: H) -> Self {
Self {
handler,
_marker: std::marker::PhantomData,
}
}
}
impl<Marker, H> Handler for HandlerFnAdapter<Marker, H>
where
Marker: Send + Sync + 'static,
H: HandlerFn<Marker>,
{
fn handle(&self, call: Call) -> HandlerFuture {
self.handler.clone().call(call)
}
}
pub trait IntoHandler<Marker> {
type Handler: Handler;
fn into_handler(self) -> Self::Handler;
}
#[doc(hidden)]
pub struct IsHandler;
impl<H: Handler> IntoHandler<IsHandler> for H {
type Handler = H;
fn into_handler(self) -> H {
self
}
}
impl<Marker, H> IntoHandler<(IsHandler, Marker)> for H
where
Marker: Send + Sync + 'static,
H: HandlerFn<Marker>,
{
type Handler = HandlerFnAdapter<Marker, H>;
fn into_handler(self) -> HandlerFnAdapter<Marker, H> {
HandlerFnAdapter::new(self)
}
}
impl Handler for BoxHandler {
fn handle(&self, call: Call) -> HandlerFuture {
(**self).handle(call)
}
}
pub fn boxed<H: Handler>(h: H) -> BoxHandler {
Arc::new(h)
}
#[cfg(test)]
mod tests {
use super::*;
use bytes::Bytes;
use http::{HeaderMap, Method, StatusCode, Uri};
fn sample_call() -> Call {
Call::new(
Method::GET,
"/".parse::<Uri>().unwrap(),
HeaderMap::new(),
Bytes::new(),
)
}
#[tokio::test]
async fn closure_returning_str_is_a_handler() {
let h = boxed((|_call: Call| async move { "hello" }).into_handler());
let res = h.handle(sample_call()).await;
assert_eq!(res.status, StatusCode::OK);
assert_eq!(res.body, Bytes::from("hello"));
}
#[tokio::test]
async fn closure_returning_result_is_a_handler() {
let h = boxed(
(|call: Call| async move {
let _ = call.path();
Ok::<_, crate::Error>((StatusCode::CREATED, "made"))
})
.into_handler(),
);
let res = h.handle(sample_call()).await;
assert_eq!(res.status, StatusCode::CREATED);
}
use crate::extract::FromCallParts;
struct Greeting(&'static str);
#[async_trait::async_trait]
impl FromCallParts for Greeting {
async fn from_call_parts(_call: &mut Call) -> crate::Result<Self> {
Ok(Greeting("hi"))
}
}
#[tokio::test]
async fn extractor_style_handler_works() {
let h = boxed((|g: Greeting| async move { g.0 }).into_handler());
let res = h.handle(sample_call()).await;
assert_eq!(res.body, bytes::Bytes::from("hi"));
}
struct ManualHandler;
impl Handler for ManualHandler {
fn handle(&self, _call: Call) -> HandlerFuture {
Box::pin(async move { "manual".into_response() })
}
}
#[tokio::test]
async fn manual_impl_handler_is_boxable() {
let h = boxed(ManualHandler);
let res = h.handle(sample_call()).await;
assert_eq!(res.body, Bytes::from("manual"));
}
#[tokio::test]
async fn box_handler_is_a_handler() {
let boxed_once: BoxHandler = boxed(ManualHandler);
let boxed_twice = boxed(boxed_once);
let res = boxed_twice.handle(sample_call()).await;
assert_eq!(res.body, Bytes::from("manual"));
}
}