2020-12-27 15:15:42 +01:00
|
|
|
use alloc::{rc::Rc, sync::Arc};
|
|
|
|
use core::{
|
|
|
|
future::Future,
|
|
|
|
marker::PhantomData,
|
|
|
|
pin::Pin,
|
|
|
|
task::{Context, Poll},
|
|
|
|
};
|
|
|
|
|
|
|
|
use pin_project_lite::pin_project;
|
2019-03-02 21:16:30 +01:00
|
|
|
|
2019-12-03 13:32:02 +01:00
|
|
|
use crate::transform_err::TransformMapInitErr;
|
2019-11-14 13:38:24 +01:00
|
|
|
use crate::{IntoServiceFactory, Service, ServiceFactory};
|
2019-02-03 19:42:27 +01:00
|
|
|
|
2019-12-11 05:29:34 +01:00
|
|
|
/// Apply transform to a service.
|
2020-12-27 05:28:00 +01:00
|
|
|
pub fn apply<T, S, I, Req>(t: T, factory: I) -> ApplyTransform<T, S, Req>
|
2019-11-20 19:35:44 +01:00
|
|
|
where
|
2020-12-27 05:28:00 +01:00
|
|
|
I: IntoServiceFactory<S, Req>,
|
|
|
|
S: ServiceFactory<Req>,
|
|
|
|
T: Transform<S::Service, Req, InitError = S::InitError>,
|
2019-11-20 19:35:44 +01:00
|
|
|
{
|
2019-12-11 05:29:34 +01:00
|
|
|
ApplyTransform::new(t, factory.into_factory())
|
2019-11-20 19:35:44 +01:00
|
|
|
}
|
|
|
|
|
2019-12-10 16:11:39 +01:00
|
|
|
/// The `Transform` trait defines the interface of a service factory that wraps inner service
|
|
|
|
/// during construction.
|
|
|
|
///
|
|
|
|
/// Transform(middleware) wraps inner service and runs during
|
|
|
|
/// inbound and/or outbound processing in the request/response lifecycle.
|
|
|
|
/// It may modify request and/or response.
|
|
|
|
///
|
|
|
|
/// For example, timeout transform:
|
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// pub struct Timeout<S> {
|
|
|
|
/// service: S,
|
|
|
|
/// timeout: Duration,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl<S> Service for Timeout<S>
|
|
|
|
/// where
|
|
|
|
/// S: Service,
|
|
|
|
/// {
|
|
|
|
/// type Request = S::Request;
|
|
|
|
/// type Response = S::Response;
|
|
|
|
/// type Error = TimeoutError<S::Error>;
|
|
|
|
/// type Future = TimeoutServiceResponse<S>;
|
|
|
|
///
|
|
|
|
/// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
/// ready!(self.service.poll_ready(cx)).map_err(TimeoutError::Service)
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn call(&mut self, req: S::Request) -> Self::Future {
|
|
|
|
/// TimeoutServiceResponse {
|
|
|
|
/// fut: self.service.call(req),
|
|
|
|
/// sleep: Delay::new(clock::now() + self.timeout),
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Timeout service in above example is decoupled from underlying service implementation
|
|
|
|
/// and could be applied to any service.
|
|
|
|
///
|
2019-07-17 06:30:59 +02:00
|
|
|
/// The `Transform` trait defines the interface of a Service factory. `Transform`
|
|
|
|
/// is often implemented for middleware, defining how to construct a
|
|
|
|
/// middleware Service. A Service that is constructed by the factory takes
|
2019-04-04 17:40:28 +02:00
|
|
|
/// the Service that follows it during execution as a parameter, assuming
|
2019-07-17 06:30:59 +02:00
|
|
|
/// ownership of the next Service.
|
2019-12-10 16:11:39 +01:00
|
|
|
///
|
|
|
|
/// Factory for `Timeout` middleware from the above example could look like this:
|
|
|
|
///
|
|
|
|
/// ```rust,,ignore
|
|
|
|
/// pub struct TimeoutTransform {
|
|
|
|
/// timeout: Duration,
|
|
|
|
/// }
|
|
|
|
///
|
2020-11-20 23:45:57 +01:00
|
|
|
/// impl<S> Transform<S> for TimeoutTransform
|
2019-12-10 16:11:39 +01:00
|
|
|
/// where
|
|
|
|
/// S: Service,
|
|
|
|
/// {
|
|
|
|
/// type Request = S::Request;
|
|
|
|
/// type Response = S::Response;
|
|
|
|
/// type Error = TimeoutError<S::Error>;
|
|
|
|
/// type InitError = S::Error;
|
|
|
|
/// type Transform = Timeout<S>;
|
|
|
|
/// type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
|
|
|
///
|
|
|
|
/// fn new_transform(&self, service: S) -> Self::Future {
|
|
|
|
/// ok(TimeoutService {
|
|
|
|
/// service,
|
|
|
|
/// timeout: self.timeout,
|
|
|
|
/// })
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
2020-12-27 05:28:00 +01:00
|
|
|
pub trait Transform<S, Req> {
|
2019-02-03 19:42:27 +01:00
|
|
|
/// Responses given by the service.
|
|
|
|
type Response;
|
|
|
|
|
|
|
|
/// Errors produced by the service.
|
|
|
|
type Error;
|
|
|
|
|
|
|
|
/// The `TransformService` value created by this factory
|
2020-12-27 05:28:00 +01:00
|
|
|
type Transform: Service<Req, Response = Self::Response, Error = Self::Error>;
|
2019-02-03 19:42:27 +01:00
|
|
|
|
2019-12-10 16:11:39 +01:00
|
|
|
/// Errors produced while building a transform service.
|
2019-02-03 19:42:27 +01:00
|
|
|
type InitError;
|
|
|
|
|
|
|
|
/// The future response value.
|
2019-11-14 13:38:24 +01:00
|
|
|
type Future: Future<Output = Result<Self::Transform, Self::InitError>>;
|
2019-02-03 19:42:27 +01:00
|
|
|
|
2019-12-10 16:11:39 +01:00
|
|
|
/// Creates and returns a new Transform component, asynchronously
|
2019-03-05 04:38:11 +01:00
|
|
|
fn new_transform(&self, service: S) -> Self::Future;
|
2019-12-03 13:32:02 +01:00
|
|
|
|
2020-09-19 16:12:41 +02:00
|
|
|
/// Map this transform's factory error to a different error,
|
2019-12-03 13:32:02 +01:00
|
|
|
/// returning a new transform service factory.
|
2020-12-27 05:28:00 +01:00
|
|
|
fn map_init_err<F, E>(self, f: F) -> TransformMapInitErr<Self, S, Req, F, E>
|
2019-12-03 13:32:02 +01:00
|
|
|
where
|
|
|
|
Self: Sized,
|
|
|
|
F: Fn(Self::InitError) -> E + Clone,
|
|
|
|
{
|
|
|
|
TransformMapInitErr::new(self, f)
|
|
|
|
}
|
2019-02-03 19:42:27 +01:00
|
|
|
}
|
|
|
|
|
2020-12-27 05:28:00 +01:00
|
|
|
impl<T, S, Req> Transform<S, Req> for Rc<T>
|
2019-02-03 19:42:27 +01:00
|
|
|
where
|
2020-12-27 05:28:00 +01:00
|
|
|
T: Transform<S, Req>,
|
2019-03-02 21:16:30 +01:00
|
|
|
{
|
|
|
|
type Response = T::Response;
|
|
|
|
type Error = T::Error;
|
|
|
|
type InitError = T::InitError;
|
2019-03-05 04:38:11 +01:00
|
|
|
type Transform = T::Transform;
|
2019-03-02 21:16:30 +01:00
|
|
|
type Future = T::Future;
|
|
|
|
|
2019-03-05 04:38:11 +01:00
|
|
|
fn new_transform(&self, service: S) -> T::Future {
|
|
|
|
self.as_ref().new_transform(service)
|
2019-03-02 21:16:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-27 05:28:00 +01:00
|
|
|
impl<T, S, Req> Transform<S, Req> for Arc<T>
|
2019-03-02 21:16:30 +01:00
|
|
|
where
|
2020-12-27 05:28:00 +01:00
|
|
|
T: Transform<S, Req>,
|
2019-03-02 21:16:30 +01:00
|
|
|
{
|
|
|
|
type Response = T::Response;
|
|
|
|
type Error = T::Error;
|
|
|
|
type InitError = T::InitError;
|
2019-03-05 04:38:11 +01:00
|
|
|
type Transform = T::Transform;
|
2019-03-02 21:16:30 +01:00
|
|
|
type Future = T::Future;
|
|
|
|
|
2019-03-05 04:38:11 +01:00
|
|
|
fn new_transform(&self, service: S) -> T::Future {
|
|
|
|
self.as_ref().new_transform(service)
|
2019-03-02 21:16:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-12 20:53:08 +01:00
|
|
|
/// `Apply` transform to new service
|
2020-12-27 05:28:00 +01:00
|
|
|
pub struct ApplyTransform<T, S, Req>(Rc<(T, S)>, PhantomData<Req>);
|
2019-03-05 06:24:47 +01:00
|
|
|
|
2020-12-27 05:28:00 +01:00
|
|
|
impl<T, S, Req> ApplyTransform<T, S, Req>
|
2019-03-05 06:24:47 +01:00
|
|
|
where
|
2020-12-27 05:28:00 +01:00
|
|
|
S: ServiceFactory<Req>,
|
|
|
|
T: Transform<S::Service, Req, InitError = S::InitError>,
|
2019-03-05 06:24:47 +01:00
|
|
|
{
|
2019-03-12 20:53:08 +01:00
|
|
|
/// Create new `ApplyTransform` new service instance
|
2019-11-14 13:38:24 +01:00
|
|
|
fn new(t: T, service: S) -> Self {
|
2020-12-27 05:28:00 +01:00
|
|
|
Self(Rc::new((t, service)), PhantomData)
|
2019-03-05 06:24:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-27 05:28:00 +01:00
|
|
|
impl<T, S, Req> Clone for ApplyTransform<T, S, Req> {
|
2019-03-12 20:53:08 +01:00
|
|
|
fn clone(&self) -> Self {
|
2020-12-27 05:28:00 +01:00
|
|
|
ApplyTransform(self.0.clone(), PhantomData)
|
2019-03-12 20:53:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-27 05:28:00 +01:00
|
|
|
impl<T, S, Req> ServiceFactory<Req> for ApplyTransform<T, S, Req>
|
2019-03-05 06:24:47 +01:00
|
|
|
where
|
2020-12-27 05:28:00 +01:00
|
|
|
S: ServiceFactory<Req>,
|
|
|
|
T: Transform<S::Service, Req, InitError = S::InitError>,
|
2019-03-05 06:24:47 +01:00
|
|
|
{
|
|
|
|
type Response = T::Response;
|
|
|
|
type Error = T::Error;
|
|
|
|
|
2019-05-12 15:03:50 +02:00
|
|
|
type Config = S::Config;
|
2019-03-05 06:24:47 +01:00
|
|
|
type Service = T::Transform;
|
|
|
|
type InitError = T::InitError;
|
2020-12-27 05:28:00 +01:00
|
|
|
type Future = ApplyTransformFuture<T, S, Req>;
|
2019-03-05 06:24:47 +01:00
|
|
|
|
2019-12-02 16:27:48 +01:00
|
|
|
fn new_service(&self, cfg: S::Config) -> Self::Future {
|
2019-03-05 06:24:47 +01:00
|
|
|
ApplyTransformFuture {
|
2019-12-05 07:37:26 +01:00
|
|
|
store: self.0.clone(),
|
2020-12-27 15:15:42 +01:00
|
|
|
state: ApplyTransformFutureState::A {
|
|
|
|
fut: self.0.as_ref().1.new_service(cfg),
|
|
|
|
},
|
2019-03-05 06:24:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-27 15:15:42 +01:00
|
|
|
pin_project! {
|
|
|
|
pub struct ApplyTransformFuture<T, S, Req>
|
|
|
|
where
|
|
|
|
S: ServiceFactory<Req>,
|
|
|
|
T: Transform<S::Service, Req, InitError = S::InitError>,
|
|
|
|
{
|
|
|
|
store: Rc<(T, S)>,
|
|
|
|
#[pin]
|
|
|
|
state: ApplyTransformFutureState<T, S, Req>,
|
|
|
|
}
|
2019-12-05 07:37:26 +01:00
|
|
|
}
|
|
|
|
|
2020-12-27 15:15:42 +01:00
|
|
|
pin_project! {
|
|
|
|
#[project = ApplyTransformFutureStateProj]
|
|
|
|
pub enum ApplyTransformFutureState<T, S, Req>
|
|
|
|
where
|
|
|
|
S: ServiceFactory<Req>,
|
|
|
|
T: Transform<S::Service, Req, InitError = S::InitError>,
|
|
|
|
{
|
|
|
|
A { #[pin] fut: S::Future },
|
|
|
|
B { #[pin] fut: T::Future },
|
|
|
|
}
|
2019-03-05 06:24:47 +01:00
|
|
|
}
|
|
|
|
|
2020-12-27 05:28:00 +01:00
|
|
|
impl<T, S, Req> Future for ApplyTransformFuture<T, S, Req>
|
2019-03-05 06:24:47 +01:00
|
|
|
where
|
2020-12-27 05:28:00 +01:00
|
|
|
S: ServiceFactory<Req>,
|
|
|
|
T: Transform<S::Service, Req, InitError = S::InitError>,
|
2019-03-05 06:24:47 +01:00
|
|
|
{
|
2019-11-14 13:38:24 +01:00
|
|
|
type Output = Result<T::Transform, T::InitError>;
|
2019-03-05 06:24:47 +01:00
|
|
|
|
2019-11-19 09:51:40 +01:00
|
|
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
|
|
let mut this = self.as_mut().project();
|
2019-11-14 13:38:24 +01:00
|
|
|
|
2019-12-05 07:37:26 +01:00
|
|
|
match this.state.as_mut().project() {
|
2020-12-27 15:15:42 +01:00
|
|
|
ApplyTransformFutureStateProj::A { fut } => match fut.poll(cx)? {
|
2019-12-05 07:37:26 +01:00
|
|
|
Poll::Ready(srv) => {
|
|
|
|
let fut = this.store.0.new_transform(srv);
|
2020-12-27 15:15:42 +01:00
|
|
|
this.state.set(ApplyTransformFutureState::B { fut });
|
2019-12-05 07:37:26 +01:00
|
|
|
self.poll(cx)
|
|
|
|
}
|
|
|
|
Poll::Pending => Poll::Pending,
|
|
|
|
},
|
2020-12-27 15:15:42 +01:00
|
|
|
ApplyTransformFutureStateProj::B { fut } => fut.poll(cx),
|
2019-03-05 06:24:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|