-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(client): allow to add a closure as a middleware in client
- Loading branch information
Showing
6 changed files
with
184 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use crate::{ | ||
error::Error, | ||
response::Response, | ||
service::{async_fn, Service, ServiceRequest}, | ||
}; | ||
|
||
/// middleware to wrap async function as a service. | ||
pub struct AsyncFn<S, F> { | ||
service: S, | ||
func: F, | ||
} | ||
|
||
impl<S, F> AsyncFn<S, F> { | ||
pub fn new(service: S, func: F) -> Self { | ||
Self { service, func } | ||
} | ||
} | ||
|
||
impl<'r, 'c, S, F> Service<ServiceRequest<'r, 'c>> for AsyncFn<S, F> | ||
where | ||
S: for<'r2, 'c2> Service<ServiceRequest<'r, 'c>, Response = Response, Error = Error> + Send + Sync, | ||
F: for<'r3, 'c3, 's3> async_fn::AsyncFn<(ServiceRequest<'r, 'c>, &'s3 S), Output = Result<Response, Error>> | ||
+ Send | ||
+ Sync, | ||
for<'r4, 'c4, 's4> <F as async_fn::AsyncFn<(ServiceRequest<'r4, 'c4>, &'s4 S)>>::Future: Send, | ||
{ | ||
type Response = Response; | ||
type Error = Error; | ||
|
||
async fn call(&self, req: ServiceRequest<'r, 'c>) -> Result<Self::Response, Self::Error> { | ||
self.func.call((req, &self.service)).await | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#![allow(non_snake_case)] | ||
|
||
use core::future::Future; | ||
|
||
/// Same as `std::ops::Fn` trait but for async output. | ||
/// | ||
/// It is necessary in the the HRTB bounds for async fn's with reference parameters because it | ||
/// allows the output future to be bound to the parameter lifetime. | ||
/// `F: for<'a> AsyncFn<(&'a u8,) Output=u8>` | ||
pub trait AsyncFn<Arg> { | ||
type Output; | ||
type Future: Future<Output = Self::Output>; | ||
|
||
fn call(&self, arg: Arg) -> Self::Future; | ||
} | ||
|
||
macro_rules! async_closure_impl { | ||
($($arg: ident),*) => { | ||
impl<Func, Fut, $($arg,)*> AsyncFn<($($arg,)*)> for Func | ||
where | ||
Func: Fn($($arg),*) -> Fut, | ||
Fut: Future, | ||
{ | ||
type Output = Fut::Output; | ||
type Future = Fut; | ||
|
||
#[inline] | ||
fn call(&self, ($($arg,)*): ($($arg,)*)) -> Self::Future { | ||
self($($arg,)*) | ||
} | ||
} | ||
} | ||
} | ||
|
||
async_closure_impl! {} | ||
async_closure_impl! { A } | ||
async_closure_impl! { A, B } | ||
async_closure_impl! { A, B, C } | ||
async_closure_impl! { A, B, C, D } | ||
async_closure_impl! { A, B, C, D, E } | ||
async_closure_impl! { A, B, C, D, E, F } | ||
async_closure_impl! { A, B, C, D, E, F, G } | ||
async_closure_impl! { A, B, C, D, E, F, G, H } | ||
async_closure_impl! { A, B, C, D, E, F, G, H, I } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
pub(crate) mod async_fn; | ||
pub(crate) mod http; | ||
|
||
use core::{future::Future, pin::Pin, time::Duration}; | ||
|
||
use crate::{body::BoxBody, client::Client, http::Request}; | ||
pub use http::HttpService; | ||
|
||
type BoxFuture<'f, T, E> = Pin<Box<dyn Future<Output = Result<T, E>> + Send + 'f>>; | ||
|
||
/// trait for composable http services. Used for middleware,resolver and tls connector. | ||
pub trait Service<Req> { | ||
type Response; | ||
type Error; | ||
|
||
fn call(&self, req: Req) -> impl Future<Output = Result<Self::Response, Self::Error>> + Send; | ||
} | ||
|
||
pub trait ServiceDyn<Req> { | ||
type Response; | ||
type Error; | ||
|
||
fn call<'s>(&'s self, req: Req) -> BoxFuture<'s, Self::Response, Self::Error> | ||
where | ||
Req: 's; | ||
} | ||
|
||
impl<S, Req> ServiceDyn<Req> for S | ||
where | ||
S: Service<Req>, | ||
{ | ||
type Response = S::Response; | ||
type Error = S::Error; | ||
|
||
#[inline] | ||
fn call<'s>(&'s self, req: Req) -> BoxFuture<'s, Self::Response, Self::Error> | ||
where | ||
Req: 's, | ||
{ | ||
Box::pin(Service::call(self, req)) | ||
} | ||
} | ||
|
||
impl<I, Req> Service<Req> for Box<I> | ||
where | ||
Req: Send, | ||
I: ServiceDyn<Req> + ?Sized + Send + Sync, | ||
{ | ||
type Response = I::Response; | ||
type Error = I::Error; | ||
|
||
#[inline] | ||
async fn call(&self, req: Req) -> Result<Self::Response, Self::Error> { | ||
ServiceDyn::call(&**self, req).await | ||
} | ||
} | ||
|
||
/// request type for middlewares. | ||
/// It's similar to [RequestBuilder] type but with additional side effect enabled. | ||
/// | ||
/// [RequestBuilder]: crate::request::RequestBuilder | ||
pub struct ServiceRequest<'r, 'c> { | ||
pub req: &'r mut Request<BoxBody>, | ||
pub client: &'c Client, | ||
pub timeout: Duration, | ||
} |