use crate::error::{Error, IntoResponse, Result};
use crate::request::Request;
use crate::response::Response;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
pub type Handler = Arc<dyn Fn(Request) -> BoxFuture<Response> + Send + Sync>;
pub type FallibleHandler =
Arc<dyn Fn(Request) -> BoxFuture<Result<Response>> + Send + Sync>;
pub(crate) type ErrorHandlerFn =
Arc<dyn Fn(Error) -> BoxFuture<Response> + Send + Sync>;
pub trait IntoHandler<T> {
fn into_handler(self) -> FallibleHandler;
}
pub struct ResponseMarker;
pub struct ResultMarker;
impl<F, Fut, R> IntoHandler<(ResponseMarker,)> for F
where
F: Fn(Request) -> Fut + Send + Sync + 'static,
Fut: Future<Output = R> + Send + 'static,
R: IntoResponse,
{
fn into_handler(self) -> FallibleHandler {
Arc::new(move |req| {
let fut = self(req);
Box::pin(async move { Ok(fut.await.into_response()) })
})
}
}
impl<F, Fut, R> IntoHandler<(ResultMarker,)> for F
where
F: Fn(Request) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<R>> + Send + 'static,
R: IntoResponse,
{
fn into_handler(self) -> FallibleHandler {
Arc::new(move |req| {
let fut = self(req);
Box::pin(async move { Ok(fut.await?.into_response()) })
})
}
}
pub trait ErrorResponse: IntoResponse {}
pub struct FallibleResponseMarker;
impl<F, Fut, R, E> IntoHandler<(FallibleResponseMarker, E)> for F
where
F: Fn(Request) -> Fut + Send + Sync + 'static,
Fut: Future<Output = std::result::Result<R, E>> + Send + 'static,
R: IntoResponse,
E: ErrorResponse + 'static,
{
fn into_handler(self) -> FallibleHandler {
Arc::new(move |req| {
let fut = self(req);
Box::pin(async move {
match fut.await {
Ok(r) => Ok(r.into_response()),
Err(e) => Ok(e.into_response()),
}
})
})
}
}
pub struct NoArgResponseMarker;
impl<F, Fut, R> IntoHandler<(NoArgResponseMarker,)> for F
where
F: Fn() -> Fut + Send + Sync + 'static,
Fut: Future<Output = R> + Send + 'static,
R: IntoResponse,
{
fn into_handler(self) -> FallibleHandler {
Arc::new(move |_req| {
let fut = self();
Box::pin(async move { Ok(fut.await.into_response()) })
})
}
}
impl IntoHandler<()> for FallibleHandler {
fn into_handler(self) -> FallibleHandler {
self
}
}
pub fn wrap_errors(handler: FallibleHandler, eh: Option<ErrorHandlerFn>) -> Handler {
Arc::new(move |req| {
let handler = Arc::clone(&handler);
let eh = eh.clone();
Box::pin(async move {
match handler(req).await {
Ok(res) => res,
Err(Error::Response(res)) => *res,
Err(err) => match &eh {
Some(hook) => hook(err).await,
None => err.into_response(),
},
}
})
})
}