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};
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a Churust handler",
label = "not a handler",
note = "a handler is an `async fn` or a closure returning a future, taking up to 8 arguments",
note = "every argument except the last must implement `FromCallParts` (it sees only the request head)",
note = "the last argument may implement `FromCall` and consume the body — `Json`, `Form`, `Bytes`, `String`, `Payload`, `Multipart`, `Either`",
note = "two body-consuming arguments cannot compile: the body is a one-shot stream",
note = "the return type must implement `IntoResponse`"
)]
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: 'static,
H: HandlerFn<Marker>,
{
fn handle(&self, call: Call) -> HandlerFuture {
self.handler.clone().call(call)
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` cannot be used as a route handler",
label = "not a valid handler",
note = "check each argument: all but the last must implement `FromCallParts`, and only the last may consume the body",
note = "a body-consuming extractor (`Json`, `Form`, `Bytes`, `String`, `Payload`, `Multipart`, `Either`) must come last, and there can be only one",
note = "`Option<T>` works where `T` implements `OptionalFromCallParts`",
note = "the closure's return type must implement `IntoResponse`; `Result<T, E>` works when both `T: IntoResponse` and `E: IntoError`"
)]
pub trait IntoHandler<Marker> {
type Handler: Handler;
fn into_handler(self) -> Self::Handler;
}
#[doc(hidden)]
pub struct IsHandler;
#[diagnostic::do_not_recommend]
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: '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"));
}
}