tsukuyomi_service/
lib.rs

1//! Abstraction of service layer in Tsukuyomi, based on [`tower-service`].
2//!
3//! [`tower-service`]: https://crates.io/crates/tower-service
4
5#![doc(html_root_url = "https://docs.rs/tsukuyomi-service/0.1.0")]
6#![deny(
7    missing_docs,
8    missing_debug_implementations,
9    nonstandard_style,
10    rust_2018_idioms,
11    rust_2018_compatibility,
12    unused
13)]
14#![forbid(clippy::unimplemented)]
15
16use futures::{Async, Future, IntoFuture, Poll};
17
18#[doc(no_inline)]
19pub use tower_service::Service;
20
21/// Creates a `Service` from a function.
22pub fn service_fn<Request, R>(
23    f: impl FnMut(Request) -> R,
24) -> impl Service<
25    Request, //
26    Response = R::Item,
27    Error = R::Error,
28    Future = R::Future,
29>
30where
31    R: IntoFuture,
32{
33    #[allow(missing_debug_implementations)]
34    struct ServiceFn<F>(F);
35
36    impl<F, Request, R> Service<Request> for ServiceFn<F>
37    where
38        F: FnMut(Request) -> R,
39        R: IntoFuture,
40    {
41        type Response = R::Item;
42        type Error = R::Error;
43        type Future = R::Future;
44
45        #[inline]
46        fn poll_ready(&mut self) -> Poll<(), Self::Error> {
47            Ok(Async::Ready(()))
48        }
49
50        #[inline]
51        fn call(&mut self, request: Request) -> Self::Future {
52            (self.0)(request).into_future()
53        }
54    }
55
56    ServiceFn(f)
57}
58
59/// A trait representing a factory of `Service`s.
60///
61/// The signature of this trait imitates `tower_util::MakeService`,
62/// but there are the following differences:
63///
64/// * This trait does not have the method `poll_ready` to check
65///   if the factory is ready for creating a `Service`.
66/// * The method `make_service` is *immutable*.
67pub trait MakeService<Ctx, Request> {
68    /// The response type returned by `Service`.
69    type Response;
70    /// The error type returned by `Service`.
71    type Error;
72    /// The type of services created by this factory.
73    type Service: Service<Request, Response = Self::Response, Error = Self::Error>;
74    /// The type of errors that occur while creating `Service`.
75    type MakeError;
76    /// The type of `Future` returned from `make_service`.
77    type Future: Future<Item = Self::Service, Error = Self::MakeError>;
78
79    /// Creates a `Future` that will return a value of `Service`.
80    fn make_service(&self, ctx: Ctx) -> Self::Future;
81}
82
83/// An *alias* of `MakeService` receiving the context value of `Ctx` as reference.
84#[allow(missing_docs)]
85pub trait MakeServiceRef<Ctx, Request> {
86    type Response;
87    type Error;
88    type Service: Service<Request, Response = Self::Response, Error = Self::Error>;
89    type MakeError;
90    type Future: Future<Item = Self::Service, Error = Self::MakeError>;
91
92    fn make_service_ref(&self, ctx: &Ctx) -> Self::Future;
93}
94
95impl<S, T, Req, Res, Err, Svc, MkErr, Fut> MakeServiceRef<T, Req> for S
96where
97    for<'a> S: MakeService<
98        &'a T,
99        Req,
100        Response = Res,
101        Error = Err,
102        Service = Svc,
103        MakeError = MkErr,
104        Future = Fut,
105    >,
106    Svc: Service<Req, Response = Res, Error = Err>,
107    Fut: Future<Item = Svc, Error = MkErr>,
108{
109    type Response = Res;
110    type Error = Err;
111    type Service = Svc;
112    type MakeError = MkErr;
113    type Future = Fut;
114
115    #[inline]
116    fn make_service_ref(&self, ctx: &T) -> Self::Future {
117        MakeService::make_service(self, ctx)
118    }
119}
120
121/// Creates a `MakeService` from a function.
122pub fn make_service<Request, Ctx, R>(
123    f: impl Fn(Ctx) -> R,
124) -> impl MakeService<
125    Ctx, //
126    Request,
127    Response = <R::Item as Service<Request>>::Response,
128    Error = <R::Item as Service<Request>>::Error,
129    Service = R::Item,
130    MakeError = R::Error,
131    Future = R::Future,
132>
133where
134    R: IntoFuture,
135    R::Item: Service<Request>,
136{
137    #[allow(missing_debug_implementations)]
138    struct MakeServiceFn<F>(F);
139
140    impl<F, Request, Ctx, R> MakeService<Ctx, Request> for MakeServiceFn<F>
141    where
142        F: Fn(Ctx) -> R,
143        R: IntoFuture,
144        R::Item: Service<Request>,
145    {
146        type Response = <R::Item as Service<Request>>::Response;
147        type Error = <R::Item as Service<Request>>::Error;
148        type Service = R::Item;
149        type MakeError = R::Error;
150        type Future = R::Future;
151
152        #[inline]
153        fn make_service(&self, ctx: Ctx) -> Self::Future {
154            (self.0)(ctx).into_future()
155        }
156    }
157
158    MakeServiceFn(f)
159}
160
161/// Creates a `ModifyServiceRef` from a function.
162pub fn make_service_ref<Request, Ctx, R>(
163    f: impl Fn(&Ctx) -> R,
164) -> impl for<'a> MakeService<
165    &'a Ctx, //
166    Request,
167    Response = <R::Item as Service<Request>>::Response,
168    Error = <R::Item as Service<Request>>::Error,
169    Service = R::Item,
170    MakeError = R::Error,
171    Future = R::Future,
172>
173where
174    R: IntoFuture,
175    R::Item: Service<Request>,
176{
177    #[allow(missing_debug_implementations)]
178    struct MakeServiceRefFn<F>(F);
179
180    impl<'a, F, Request, Ctx, R> MakeService<&'a Ctx, Request> for MakeServiceRefFn<F>
181    where
182        F: Fn(&Ctx) -> R,
183        R: IntoFuture,
184        R::Item: Service<Request>,
185    {
186        type Response = <R::Item as Service<Request>>::Response;
187        type Error = <R::Item as Service<Request>>::Error;
188        type Service = R::Item;
189        type MakeError = R::Error;
190        type Future = R::Future;
191
192        #[inline]
193        fn make_service(&self, ctx: &'a Ctx) -> Self::Future {
194            (self.0)(ctx).into_future()
195        }
196    }
197
198    MakeServiceRefFn(f)
199}
200
201/// A trait representing the modification of `Service` to another one.
202pub trait ModifyService<Ctx, Request, S> {
203    /// The response type returned by the modified `Service`.
204    type Response;
205    /// The error type returned by the modified `Service`.
206    type Error;
207    /// The type of modified service.
208    type Service: Service<Request, Response = Self::Response, Error = Self::Error>;
209    /// The error that occurs when modifying services.
210    type ModifyError;
211    /// The type of `Future` returned from `modify_service`.
212    type Future: Future<Item = Self::Service, Error = Self::ModifyError>;
213
214    /// Modifies a service using the specified context.
215    fn modify_service(&self, input: S, ctx: Ctx) -> Self::Future;
216}
217
218impl<Ctx, Request, S> ModifyService<Ctx, Request, S> for ()
219where
220    S: Service<Request>,
221{
222    type Response = S::Response;
223    type Error = S::Error;
224    type Service = S;
225    type ModifyError = std::io::Error;
226    type Future = futures::future::FutureResult<Self::Service, Self::ModifyError>;
227
228    #[inline]
229    fn modify_service(&self, input: S, _: Ctx) -> Self::Future {
230        futures::future::ok(input)
231    }
232}
233
234/// An *alias* of `ModifyService` receiving the context value of `Ctx` as reference.
235#[allow(missing_docs)]
236pub trait ModifyServiceRef<Ctx, Request, S> {
237    type Response;
238    type Error;
239    type Service: Service<Request, Response = Self::Response, Error = Self::Error>;
240    type ModifyError;
241    type Future: Future<Item = Self::Service, Error = Self::ModifyError>;
242
243    fn modify_service_ref(&self, input: S, ctx: &Ctx) -> Self::Future;
244}
245
246impl<M, SvcIn, SvcOut, Ctx, Req, Res, Err, ModErr, Fut> ModifyServiceRef<Ctx, Req, SvcIn> for M
247where
248    for<'a> M: ModifyService<
249        &'a Ctx,
250        Req,
251        SvcIn,
252        Response = Res,
253        Error = Err,
254        Service = SvcOut,
255        ModifyError = ModErr,
256        Future = Fut,
257    >,
258    SvcOut: Service<Req, Response = Res, Error = Err>,
259    Fut: Future<Item = SvcOut, Error = ModErr>,
260{
261    type Response = Res;
262    type Error = Err;
263    type Service = SvcOut;
264    type ModifyError = ModErr;
265    type Future = Fut;
266
267    fn modify_service_ref(&self, input: SvcIn, ctx: &Ctx) -> Self::Future {
268        ModifyService::modify_service(self, input, ctx)
269    }
270}
271
272/// Creates a `ModifyService` from a function.
273pub fn modify_service<Request, S, Ctx, R>(
274    f: impl Fn(S, Ctx) -> R,
275) -> impl ModifyService<
276    Ctx, //
277    Request,
278    S,
279    Response = <R::Item as Service<Request>>::Response,
280    Error = <R::Item as Service<Request>>::Error,
281    Service = R::Item,
282    ModifyError = R::Error,
283    Future = R::Future,
284>
285where
286    R: IntoFuture,
287    R::Item: Service<Request>,
288{
289    #[allow(missing_debug_implementations)]
290    struct ModifyServiceFn<F>(F);
291
292    impl<F, Request, S, Ctx, R> ModifyService<Ctx, Request, S> for ModifyServiceFn<F>
293    where
294        F: Fn(S, Ctx) -> R,
295        R: IntoFuture,
296        R::Item: Service<Request>,
297    {
298        type Response = <R::Item as Service<Request>>::Response;
299        type Error = <R::Item as Service<Request>>::Error;
300        type Service = R::Item;
301        type ModifyError = R::Error;
302        type Future = R::Future;
303
304        #[inline]
305        fn modify_service(&self, input: S, ctx: Ctx) -> Self::Future {
306            (self.0)(input, ctx).into_future()
307        }
308    }
309
310    ModifyServiceFn(f)
311}
312
313/// Creates a `ModifyServiceRef` from a function.
314pub fn modify_service_ref<Request, S, Ctx, R>(
315    f: impl Fn(S, &Ctx) -> R,
316) -> impl for<'a> ModifyService<
317    &'a Ctx, //
318    Request,
319    S,
320    Response = <R::Item as Service<Request>>::Response,
321    Error = <R::Item as Service<Request>>::Error,
322    Service = R::Item,
323    ModifyError = R::Error,
324    Future = R::Future,
325>
326where
327    R: IntoFuture,
328    R::Item: Service<Request>,
329{
330    #[allow(missing_debug_implementations)]
331    struct ModifyServiceRefFn<F>(F);
332
333    impl<'a, F, Request, S, Ctx, R> ModifyService<&'a Ctx, Request, S> for ModifyServiceRefFn<F>
334    where
335        F: Fn(S, &Ctx) -> R,
336        R: IntoFuture,
337        R::Item: Service<Request>,
338    {
339        type Response = <R::Item as Service<Request>>::Response;
340        type Error = <R::Item as Service<Request>>::Error;
341        type Service = R::Item;
342        type ModifyError = R::Error;
343        type Future = R::Future;
344
345        #[inline]
346        fn modify_service(&self, input: S, ctx: &'a Ctx) -> Self::Future {
347            (self.0)(input, ctx).into_future()
348        }
349    }
350
351    ModifyServiceRefFn(f)
352}