requiem_service/
transform.rs

1use std::future::Future;
2use std::pin::Pin;
3use std::rc::Rc;
4use std::sync::Arc;
5use std::task::{Context, Poll};
6
7use crate::transform_err::TransformMapInitErr;
8use crate::{IntoServiceFactory, Service, ServiceFactory};
9
10/// Apply transform to a service.
11pub fn apply<T, S, U>(t: T, factory: U) -> ApplyTransform<T, S>
12where
13    S: ServiceFactory,
14    T: Transform<S::Service, InitError = S::InitError>,
15    U: IntoServiceFactory<S>,
16{
17    ApplyTransform::new(t, factory.into_factory())
18}
19
20/// The `Transform` trait defines the interface of a service factory that wraps inner service
21/// during construction.
22///
23/// Transform(middleware) wraps inner service and runs during
24/// inbound and/or outbound processing in the request/response lifecycle.
25/// It may modify request and/or response.
26///
27/// For example, timeout transform:
28///
29/// ```rust,ignore
30/// pub struct Timeout<S> {
31///     service: S,
32///     timeout: Duration,
33/// }
34///
35/// impl<S> Service for Timeout<S>
36/// where
37///     S: Service,
38/// {
39///     type Request = S::Request;
40///     type Response = S::Response;
41///     type Error = TimeoutError<S::Error>;
42///     type Future = TimeoutServiceResponse<S>;
43///
44///     fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
45///         ready!(self.service.poll_ready(cx)).map_err(TimeoutError::Service)
46///     }
47///
48///     fn call(&mut self, req: S::Request) -> Self::Future {
49///         TimeoutServiceResponse {
50///             fut: self.service.call(req),
51///             sleep: Delay::new(clock::now() + self.timeout),
52///         }
53///     }
54/// }
55/// ```
56///
57/// Timeout service in above example is decoupled from underlying service implementation
58/// and could be applied to any service.
59///
60/// The `Transform` trait defines the interface of a Service factory. `Transform`
61/// is often implemented for middleware, defining how to construct a
62/// middleware Service. A Service that is constructed by the factory takes
63/// the Service that follows it during execution as a parameter, assuming
64/// ownership of the next Service.
65///
66/// Factory for `Timeout` middleware from the above example could look like this:
67///
68/// ```rust,,ignore
69/// pub struct TimeoutTransform {
70///     timeout: Duration,
71/// }
72///
73/// impl<S> Transform<S> for TimeoutTransform<E>
74/// where
75///     S: Service,
76/// {
77///     type Request = S::Request;
78///     type Response = S::Response;
79///     type Error = TimeoutError<S::Error>;
80///     type InitError = S::Error;
81///     type Transform = Timeout<S>;
82///     type Future = Ready<Result<Self::Transform, Self::InitError>>;
83///
84///     fn new_transform(&self, service: S) -> Self::Future {
85///         ok(TimeoutService {
86///             service,
87///             timeout: self.timeout,
88///         })
89///     }
90/// }
91/// ```
92pub trait Transform<S> {
93    /// Requests handled by the service.
94    type Request;
95
96    /// Responses given by the service.
97    type Response;
98
99    /// Errors produced by the service.
100    type Error;
101
102    /// The `TransformService` value created by this factory
103    type Transform: Service<
104        Request = Self::Request,
105        Response = Self::Response,
106        Error = Self::Error,
107    >;
108
109    /// Errors produced while building a transform service.
110    type InitError;
111
112    /// The future response value.
113    type Future: Future<Output = Result<Self::Transform, Self::InitError>>;
114
115    /// Creates and returns a new Transform component, asynchronously
116    fn new_transform(&self, service: S) -> Self::Future;
117
118    /// Map this transforms's factory error to a different error,
119    /// returning a new transform service factory.
120    fn map_init_err<F, E>(self, f: F) -> TransformMapInitErr<Self, S, F, E>
121    where
122        Self: Sized,
123        F: Fn(Self::InitError) -> E + Clone,
124    {
125        TransformMapInitErr::new(self, f)
126    }
127}
128
129impl<T, S> Transform<S> for Rc<T>
130where
131    T: Transform<S>,
132{
133    type Request = T::Request;
134    type Response = T::Response;
135    type Error = T::Error;
136    type InitError = T::InitError;
137    type Transform = T::Transform;
138    type Future = T::Future;
139
140    fn new_transform(&self, service: S) -> T::Future {
141        self.as_ref().new_transform(service)
142    }
143}
144
145impl<T, S> Transform<S> for Arc<T>
146where
147    T: Transform<S>,
148{
149    type Request = T::Request;
150    type Response = T::Response;
151    type Error = T::Error;
152    type InitError = T::InitError;
153    type Transform = T::Transform;
154    type Future = T::Future;
155
156    fn new_transform(&self, service: S) -> T::Future {
157        self.as_ref().new_transform(service)
158    }
159}
160
161/// `Apply` transform to new service
162pub struct ApplyTransform<T, S>(Rc<(T, S)>);
163
164impl<T, S> ApplyTransform<T, S>
165where
166    S: ServiceFactory,
167    T: Transform<S::Service, InitError = S::InitError>,
168{
169    /// Create new `ApplyTransform` new service instance
170    fn new(t: T, service: S) -> Self {
171        Self(Rc::new((t, service)))
172    }
173}
174
175impl<T, S> Clone for ApplyTransform<T, S> {
176    fn clone(&self) -> Self {
177        ApplyTransform(self.0.clone())
178    }
179}
180
181impl<T, S> ServiceFactory for ApplyTransform<T, S>
182where
183    S: ServiceFactory,
184    T: Transform<S::Service, InitError = S::InitError>,
185{
186    type Request = T::Request;
187    type Response = T::Response;
188    type Error = T::Error;
189
190    type Config = S::Config;
191    type Service = T::Transform;
192    type InitError = T::InitError;
193    type Future = ApplyTransformFuture<T, S>;
194
195    fn new_service(&self, cfg: S::Config) -> Self::Future {
196        ApplyTransformFuture {
197            store: self.0.clone(),
198            state: ApplyTransformFutureState::A(self.0.as_ref().1.new_service(cfg)),
199        }
200    }
201}
202
203#[pin_project::pin_project]
204pub struct ApplyTransformFuture<T, S>
205where
206    S: ServiceFactory,
207    T: Transform<S::Service, InitError = S::InitError>,
208{
209    store: Rc<(T, S)>,
210    #[pin]
211    state: ApplyTransformFutureState<T, S>,
212}
213
214#[pin_project::pin_project]
215pub enum ApplyTransformFutureState<T, S>
216where
217    S: ServiceFactory,
218    T: Transform<S::Service, InitError = S::InitError>,
219{
220    A(#[pin] S::Future),
221    B(#[pin] T::Future),
222}
223
224impl<T, S> Future for ApplyTransformFuture<T, S>
225where
226    S: ServiceFactory,
227    T: Transform<S::Service, InitError = S::InitError>,
228{
229    type Output = Result<T::Transform, T::InitError>;
230
231    #[pin_project::project]
232    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
233        let mut this = self.as_mut().project();
234
235        #[project]
236        match this.state.as_mut().project() {
237            ApplyTransformFutureState::A(fut) => match fut.poll(cx)? {
238                Poll::Ready(srv) => {
239                    let fut = this.store.0.new_transform(srv);
240                    this.state.set(ApplyTransformFutureState::B(fut));
241                    self.poll(cx)
242                }
243                Poll::Pending => Poll::Pending,
244            },
245            ApplyTransformFutureState::B(fut) => fut.poll(cx),
246        }
247    }
248}