use crate::body::AsyncBody;
use http::{Request, Response};
use std::{error::Error, fmt, future::Future, pin::Pin};
mod context;
mod obj;
pub use self::context::Context;
pub(crate) use self::{context::Invoke, obj::InterceptorObj};
type InterceptorResult<E> = Result<Response<AsyncBody>, E>;
#[cfg(feature = "unstable-interceptors")]
#[macro_export]
macro_rules! interceptor {
($request:ident, $ctx:ident, $body:expr) => {{
async fn interceptor(
mut $request: $crate::http::Request<$crate::AsyncBody>,
$ctx: $crate::interceptor::Context<'_>,
) -> Result<$crate::http::Response<$crate::AsyncBody>, $crate::Error> {
(move || async move { $body })().await.map_err(Into::into)
}
$crate::interceptor::from_fn(interceptor)
}};
}
pub trait Interceptor: Send + Sync {
type Err: Error + Send + Sync + 'static;
fn intercept<'a>(
&'a self,
request: Request<AsyncBody>,
ctx: Context<'a>,
) -> InterceptorFuture<'a, Self::Err>;
}
pub type InterceptorFuture<'a, E> = Pin<Box<dyn Future<Output = InterceptorResult<E>> + Send + 'a>>;
pub fn from_fn<F, E>(f: F) -> InterceptorFn<F>
where
F: for<'a> private::AsyncFn2<Request<AsyncBody>, Context<'a>, Output = InterceptorResult<E>>
+ Send
+ Sync
+ 'static,
E: Error + Send + Sync + 'static,
{
InterceptorFn(f)
}
pub struct InterceptorFn<F>(F);
impl<E, F> Interceptor for InterceptorFn<F>
where
E: Error + Send + Sync + 'static,
F: for<'a> private::AsyncFn2<Request<AsyncBody>, Context<'a>, Output = InterceptorResult<E>>
+ Send
+ Sync
+ 'static,
{
type Err = E;
fn intercept<'a>(
&self,
request: Request<AsyncBody>,
ctx: Context<'a>,
) -> InterceptorFuture<'a, Self::Err> {
Box::pin(self.0.call(request, ctx))
}
}
impl<F: fmt::Debug> fmt::Debug for InterceptorFn<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[allow(unreachable_pub)]
mod private {
use std::future::Future;
macro_rules! impl_async_fn {
($(($FnOnce:ident, $FnMut:ident, $Fn:ident, ($($arg:ident: $arg_ty:ident,)*)),)*) => {
$(
pub trait $FnOnce<$($arg_ty,)*> {
type Output;
type Future: Future<Output = Self::Output> + Send;
fn call_once(self, $($arg: $arg_ty,)*) -> Self::Future;
}
pub trait $FnMut<$($arg_ty,)*>: $FnOnce<$($arg_ty,)*> {
fn call_mut(&mut self, $($arg: $arg_ty,)*) -> Self::Future;
}
pub trait $Fn<$($arg_ty,)*>: $FnMut<$($arg_ty,)*> {
fn call(&self, $($arg: $arg_ty,)*) -> Self::Future;
}
impl<$($arg_ty,)* F, Fut> $FnOnce<$($arg_ty,)*> for F
where
F: FnOnce($($arg_ty,)*) -> Fut,
Fut: Future + Send,
{
type Output = Fut::Output;
type Future = Fut;
fn call_once(self, $($arg: $arg_ty,)*) -> Self::Future {
self($($arg,)*)
}
}
impl<$($arg_ty,)* F, Fut> $FnMut<$($arg_ty,)*> for F
where
F: FnMut($($arg_ty,)*) -> Fut,
Fut: Future + Send,
{
fn call_mut(&mut self, $($arg: $arg_ty,)*) -> Self::Future {
self($($arg,)*)
}
}
impl<$($arg_ty,)* F, Fut> $Fn<$($arg_ty,)*> for F
where
F: Fn($($arg_ty,)*) -> Fut,
Fut: Future + Send,
{
fn call(&self, $($arg: $arg_ty,)*) -> Self::Future {
self($($arg,)*)
}
}
)*
}
}
impl_async_fn! {
(AsyncFnOnce0, AsyncFnMut0, AsyncFn0, ()),
(AsyncFnOnce1, AsyncFnMut1, AsyncFn1, (a0:A0, )),
(AsyncFnOnce2, AsyncFnMut2, AsyncFn2, (a0:A0, a1:A1, )),
}
}