use futures_util::FutureExt;
use std::future::Future;
use std::panic::RefUnwindSafe;
use std::pin::Pin;
use crate::extractor::{PathExtractor, QueryStringExtractor};
use crate::handler::{
DirHandler, FileHandler, FileOptions, FilePathExtractor, Handler, HandlerError, HandlerFuture,
HandlerResult, IntoResponse, NewHandler,
};
use crate::helpers::http::Body;
use crate::pipeline::PipelineHandleChain;
use crate::router::builder::{
ExtendRouteMatcher, ReplacePathExtractor, ReplaceQueryStringExtractor, SingleRouteBuilder,
};
use crate::router::route::dispatch::DispatcherImpl;
use crate::router::route::matcher::RouteMatcher;
use crate::router::route::{Delegation, Extractors, RouteImpl};
use crate::state::State;
pub trait HandlerMarker {
fn call_and_wrap(self, state: State) -> Pin<Box<HandlerFuture>>;
}
pub trait AsyncHandlerFn<'a> {
type Res: IntoResponse + 'static;
type Fut: std::future::Future<Output = Result<Self::Res, HandlerError>> + Send + 'a;
fn call(self, arg: &'a mut State) -> Self::Fut;
}
impl<'a, Fut, R, F> AsyncHandlerFn<'a> for F
where
F: FnOnce(&'a mut State) -> Fut,
R: IntoResponse + 'static,
Fut: std::future::Future<Output = Result<R, HandlerError>> + Send + 'a,
{
type Res = R;
type Fut = Fut;
fn call(self, state: &'a mut State) -> Fut {
self(state)
}
}
impl<F, R> HandlerMarker for F
where
R: IntoResponse + 'static,
for<'a> F: AsyncHandlerFn<'a, Res = R> + Send + 'static,
{
fn call_and_wrap(self, mut state: State) -> Pin<Box<HandlerFuture>> {
async move {
let fut = self.call(&mut state);
let result = fut.await;
match result {
Ok(data) => {
let response = data.into_response(&state);
Ok((state, response))
}
Err(err) => Err((state, err)),
}
}
.boxed()
}
}
pub trait DefineSingleRoute {
fn to<H>(self, handler: H)
where
H: Handler + RefUnwindSafe + Copy + Send + Sync + 'static;
fn to_async<H, Fut>(self, handler: H)
where
Self: Sized,
H: (FnOnce(State) -> Fut) + RefUnwindSafe + Copy + Send + Sync + 'static,
Fut: Future<Output = HandlerResult> + Send + 'static;
fn to_async_borrowing<F>(self, handler: F)
where
Self: Sized,
F: HandlerMarker + Copy + Send + Sync + RefUnwindSafe + 'static;
fn to_new_handler<NH>(self, new_handler: NH)
where
NH: NewHandler + 'static;
fn to_dir<P>(self, options: P)
where
Self: ReplacePathExtractor<FilePathExtractor> + Sized,
Self::Output: DefineSingleRoute,
FileOptions: From<P>,
{
self.with_path_extractor::<FilePathExtractor>()
.to_new_handler(DirHandler::new(options));
}
fn to_file<P>(self, options: P)
where
Self: Sized,
FileOptions: From<P>,
{
self.to_new_handler(FileHandler::new(options));
}
fn with_path_extractor<NPE>(self) -> <Self as ReplacePathExtractor<NPE>>::Output
where
NPE: PathExtractor<Body> + Send + Sync + 'static,
Self: ReplacePathExtractor<NPE>,
Self::Output: DefineSingleRoute;
fn with_query_string_extractor<NQSE>(
self,
) -> <Self as ReplaceQueryStringExtractor<NQSE>>::Output
where
NQSE: QueryStringExtractor<Body> + Send + Sync + 'static,
Self: ReplaceQueryStringExtractor<NQSE>,
Self::Output: DefineSingleRoute;
fn add_route_matcher<NRM>(self, matcher: NRM) -> <Self as ExtendRouteMatcher<NRM>>::Output
where
NRM: RouteMatcher + Send + Sync + 'static,
Self: ExtendRouteMatcher<NRM>,
Self::Output: DefineSingleRoute;
}
impl<'a, M, C, P, PE, QSE> DefineSingleRoute for SingleRouteBuilder<'a, M, C, P, PE, QSE>
where
M: RouteMatcher + Send + Sync + 'static,
C: PipelineHandleChain<P> + Send + Sync + 'static,
P: RefUnwindSafe + Send + Sync + 'static,
PE: PathExtractor<Body> + Send + Sync + 'static,
QSE: QueryStringExtractor<Body> + Send + Sync + 'static,
{
fn to<H>(self, handler: H)
where
H: Handler + RefUnwindSafe + Copy + Send + Sync + 'static,
{
self.to_new_handler(move || Ok(handler))
}
fn to_async<H, Fut>(self, handler: H)
where
Self: Sized,
H: (FnOnce(State) -> Fut) + RefUnwindSafe + Copy + Send + Sync + 'static,
Fut: Future<Output = HandlerResult> + Send + 'static,
{
self.to_new_handler(move || Ok(move |s: State| handler(s).boxed()))
}
fn to_async_borrowing<F>(self, handler: F)
where
Self: Sized,
F: HandlerMarker + Copy + Send + Sync + RefUnwindSafe + 'static,
{
self.to_new_handler(move || Ok(move |state: State| handler.call_and_wrap(state)))
}
fn to_new_handler<NH>(self, new_handler: NH)
where
NH: NewHandler + 'static,
{
let dispatcher = DispatcherImpl::new(new_handler, self.pipeline_chain, self.pipelines);
let route: RouteImpl<M, PE, QSE> = RouteImpl::new(
self.matcher,
Box::new(dispatcher),
Extractors::new(),
Delegation::Internal,
);
self.node_builder.add_route(Box::new(route));
}
fn with_path_extractor<NPE>(self) -> <Self as ReplacePathExtractor<NPE>>::Output
where
NPE: PathExtractor<Body> + Send + Sync + 'static,
{
self.replace_path_extractor()
}
fn with_query_string_extractor<NQSE>(
self,
) -> <Self as ReplaceQueryStringExtractor<NQSE>>::Output
where
NQSE: QueryStringExtractor<Body> + Send + Sync + 'static,
{
self.replace_query_string_extractor()
}
fn add_route_matcher<NRM>(self, matcher: NRM) -> <Self as ExtendRouteMatcher<NRM>>::Output
where
NRM: RouteMatcher + Send + Sync + 'static,
{
self.extend_route_matcher(matcher)
}
}