ntex_service/
lib.rs

1//! See [`Service`] docs for information on this crate's foundational trait.
2#![allow(async_fn_in_trait)]
3#![deny(
4    rust_2018_idioms,
5    warnings,
6    unreachable_pub,
7    missing_debug_implementations
8)]
9use std::{rc::Rc, task::Context};
10
11mod and_then;
12mod apply;
13pub mod boxed;
14pub mod cfg;
15mod chain;
16mod ctx;
17mod fn_service;
18mod fn_shutdown;
19mod macros;
20mod map;
21mod map_config;
22mod map_err;
23mod map_init_err;
24mod middleware;
25mod pipeline;
26mod then;
27mod util;
28
29pub use self::apply::{apply_fn, apply_fn_factory};
30pub use self::chain::{chain, chain_factory};
31pub use self::ctx::ServiceCtx;
32pub use self::fn_service::{fn_factory, fn_factory_with_config, fn_service};
33pub use self::fn_shutdown::fn_shutdown;
34pub use self::map_config::{map_config, unit_config};
35pub use self::middleware::{Identity, Middleware, Stack, apply};
36pub use self::pipeline::{Pipeline, PipelineBinding, PipelineCall};
37
38#[allow(unused_variables)]
39/// An asynchronous function of `Request` to a `Response`.
40///
41/// The `Service` trait represents a request/response interaction, receiving requests and returning
42/// replies. You can think about service as a function with one argument that returns some result
43/// asynchronously. Conceptually, the operation looks like this:
44///
45/// ```rust,ignore
46/// async fn(Request) -> Result<Response, Error>
47/// ```
48///
49/// The `Service` trait just generalizes this form. Requests are defined as a generic type parameter
50/// and responses and other details are defined as associated types on the trait impl. Notice that
51/// this design means that services can receive many request types and converge them to a single
52/// response type.
53///
54/// Services can also have mutable state that influence computation by using a `Cell`, `RefCell`
55/// or `Mutex`. Services intentionally do not take `&mut self` to reduce overhead in the
56/// common cases.
57///
58/// `Service` provides a symmetric and uniform API; the same abstractions can be used to represent
59/// both clients and servers. Services describe only _transformation_ operations which encourage
60/// simple API surfaces. This leads to simpler design of each service, improves test-ability and
61/// makes composition easier.
62///
63/// ```rust
64/// # use std::convert::Infallible;
65/// #
66/// # use ntex_service::{Service, ServiceCtx};
67///
68/// struct MyService;
69///
70/// impl Service<u8> for MyService {
71///     type Response = u64;
72///     type Error = Infallible;
73///
74///     async fn call(&self, req: u8, ctx: ServiceCtx<'_, Self>) -> Result<Self::Response, Self::Error> {
75///         Ok(req as u64)
76///     }
77/// }
78/// ```
79///
80/// Sometimes it is not necessary to implement the Service trait. For example, the above service
81/// could be rewritten as a simple function and passed to [`fn_service`](fn_service()).
82///
83/// ```rust,ignore
84/// async fn my_service(req: u8) -> Result<u64, Infallible>;
85/// ```
86///
87/// Service cannot be called directly, it must be wrapped to an instance of [`Pipeline``] or
88/// by using `ctx` argument of the call method in case of chanined services.
89///
90pub trait Service<Req> {
91    /// Responses given by the service.
92    type Response;
93
94    /// Errors produced by the service when polling readiness or executing call.
95    type Error;
96
97    /// Process the request and return the response asynchronously.
98    ///
99    /// This function is expected to be callable off-task. As such, implementations of `call`
100    /// should take care to not call `poll_ready`. Caller of the service verifies readiness,
101    /// Only way to make a `call` is to use `ctx` argument, it enforces readiness before calling
102    /// service.
103    async fn call(
104        &self,
105        req: Req,
106        ctx: ServiceCtx<'_, Self>,
107    ) -> Result<Self::Response, Self::Error>;
108
109    #[inline]
110    /// Returns when the service is able to process requests.
111    ///
112    /// If the service is at capacity, then `ready` does not returns and the task is notified when
113    /// the service becomes ready again. This function is expected to be called while on a task.
114    ///
115    /// This is a **best effort** implementation. False positives are permitted. It is permitted for
116    /// the service to returns from a `ready` call and the next invocation of `call`
117    /// results in an error.
118    async fn ready(&self, ctx: ServiceCtx<'_, Self>) -> Result<(), Self::Error> {
119        Ok(())
120    }
121
122    #[inline]
123    /// Shutdown service.
124    ///
125    /// Returns when the service is properly shutdowns.
126    async fn shutdown(&self) {}
127
128    #[inline]
129    /// Polls service from the current task.
130    ///
131    /// Service may require to execute asynchronous computation or
132    /// maintain asynchronous state.
133    fn poll(&self, cx: &mut Context<'_>) -> Result<(), Self::Error> {
134        Ok(())
135    }
136
137    #[inline]
138    /// Map this service's output to a different type, returning a new service of the resulting type.
139    ///
140    /// This function is similar to the `Option::map` or `Iterator::map` where it will change
141    /// the type of the underlying service.
142    ///
143    /// Note that this function consumes the receiving service and returns a wrapped version of it,
144    /// similar to the existing `map` methods in the standard library.
145    fn map<F, Res>(self, f: F) -> dev::ServiceChain<dev::Map<Self, F, Req, Res>, Req>
146    where
147        Self: Sized,
148        F: Fn(Self::Response) -> Res,
149    {
150        chain(dev::Map::new(self, f))
151    }
152
153    #[inline]
154    /// Map this service's error to a different error, returning a new service.
155    ///
156    /// This function is similar to the `Result::map_err` where it will change the error type of
157    /// the underlying service. This is useful for example to ensure that services have the same
158    /// error type.
159    ///
160    /// Note that this function consumes the receiving service and returns a wrapped version of it.
161    fn map_err<F, E>(self, f: F) -> dev::ServiceChain<dev::MapErr<Self, F, E>, Req>
162    where
163        Self: Sized,
164        F: Fn(Self::Error) -> E,
165    {
166        chain(dev::MapErr::new(self, f))
167    }
168}
169
170/// Factory for creating `Service`s.
171///
172/// This is useful for cases where new `Service`s must be produced. One case is a TCP server
173/// listener: a listener accepts new connections, constructs a new `Service` for each using
174/// the `ServiceFactory` trait, and uses the new `Service` to process inbound requests on that
175/// new connection.
176///
177/// `Config` is a service factory configuration type.
178///
179/// Simple factories may be able to use [`fn_factory`] or [`fn_factory_with_config`] to
180/// reduce boilerplate.
181pub trait ServiceFactory<Req, Cfg = ()> {
182    /// Responses given by the created services.
183    type Response;
184
185    /// Errors produced by the created services.
186    type Error;
187
188    /// The kind of `Service` created by this factory.
189    type Service: Service<Req, Response = Self::Response, Error = Self::Error>;
190
191    /// Errors potentially raised while building a service.
192    type InitError;
193
194    /// Create and return a new service value asynchronously.
195    async fn create(&self, cfg: Cfg) -> Result<Self::Service, Self::InitError>;
196
197    #[inline]
198    /// Create and return a new service value asynchronously and wrap into a container
199    async fn pipeline(&self, cfg: Cfg) -> Result<Pipeline<Self::Service>, Self::InitError>
200    where
201        Self: Sized,
202    {
203        Ok(Pipeline::new(self.create(cfg).await?))
204    }
205
206    #[inline]
207    /// Map this service's output to a different type, returning a new service
208    /// of the resulting type.
209    fn map<F, Res>(
210        self,
211        f: F,
212    ) -> dev::ServiceChainFactory<dev::MapFactory<Self, F, Req, Res, Cfg>, Req, Cfg>
213    where
214        Self: Sized,
215        F: Fn(Self::Response) -> Res + Clone,
216    {
217        chain_factory(dev::MapFactory::new(self, f))
218    }
219
220    #[inline]
221    /// Map this service's error to a different error, returning a new service.
222    fn map_err<F, E>(
223        self,
224        f: F,
225    ) -> dev::ServiceChainFactory<dev::MapErrFactory<Self, Req, Cfg, F, E>, Req, Cfg>
226    where
227        Self: Sized,
228        F: Fn(Self::Error) -> E + Clone,
229    {
230        chain_factory(dev::MapErrFactory::new(self, f))
231    }
232
233    #[inline]
234    /// Map this factory's init error to a different error, returning a new service.
235    fn map_init_err<F, E>(
236        self,
237        f: F,
238    ) -> dev::ServiceChainFactory<dev::MapInitErr<Self, Req, Cfg, F, E>, Req, Cfg>
239    where
240        Self: Sized,
241        F: Fn(Self::InitError) -> E + Clone,
242    {
243        chain_factory(dev::MapInitErr::new(self, f))
244    }
245}
246
247impl<S, Req> Service<Req> for &S
248where
249    S: Service<Req>,
250{
251    type Response = S::Response;
252    type Error = S::Error;
253
254    #[inline]
255    async fn ready(&self, ctx: ServiceCtx<'_, Self>) -> Result<(), S::Error> {
256        ctx.ready(&**self).await
257    }
258
259    #[inline]
260    fn poll(&self, cx: &mut Context<'_>) -> Result<(), S::Error> {
261        (**self).poll(cx)
262    }
263
264    #[inline]
265    async fn shutdown(&self) {
266        (**self).shutdown().await
267    }
268
269    #[inline]
270    async fn call(
271        &self,
272        request: Req,
273        ctx: ServiceCtx<'_, Self>,
274    ) -> Result<Self::Response, Self::Error> {
275        ctx.call_nowait(&**self, request).await
276    }
277}
278
279impl<S, Req> Service<Req> for Box<S>
280where
281    S: Service<Req>,
282{
283    type Response = S::Response;
284    type Error = S::Error;
285
286    #[inline]
287    async fn ready(&self, ctx: ServiceCtx<'_, Self>) -> Result<(), S::Error> {
288        ctx.ready(&**self).await
289    }
290
291    #[inline]
292    async fn shutdown(&self) {
293        (**self).shutdown().await
294    }
295
296    #[inline]
297    async fn call(
298        &self,
299        request: Req,
300        ctx: ServiceCtx<'_, Self>,
301    ) -> Result<Self::Response, Self::Error> {
302        ctx.call_nowait(&**self, request).await
303    }
304
305    #[inline]
306    fn poll(&self, cx: &mut Context<'_>) -> Result<(), S::Error> {
307        (**self).poll(cx)
308    }
309}
310
311impl<S, Req, Cfg> ServiceFactory<Req, Cfg> for Rc<S>
312where
313    S: ServiceFactory<Req, Cfg>,
314{
315    type Response = S::Response;
316    type Error = S::Error;
317    type Service = S::Service;
318    type InitError = S::InitError;
319
320    async fn create(&self, cfg: Cfg) -> Result<Self::Service, Self::InitError> {
321        self.as_ref().create(cfg).await
322    }
323}
324
325/// Trait for types that can be converted to a `Service`
326pub trait IntoService<Svc, Req>
327where
328    Svc: Service<Req>,
329{
330    /// Convert to a `Service`
331    fn into_service(self) -> Svc;
332}
333
334/// Trait for types that can be converted to a `ServiceFactory`
335pub trait IntoServiceFactory<T, Req, Cfg = ()>
336where
337    T: ServiceFactory<Req, Cfg>,
338{
339    /// Convert `Self` to a `ServiceFactory`
340    fn into_factory(self) -> T;
341}
342
343impl<Svc, Req> IntoService<Svc, Req> for Svc
344where
345    Svc: Service<Req>,
346{
347    #[inline]
348    fn into_service(self) -> Svc {
349        self
350    }
351}
352
353impl<T, Req, Cfg> IntoServiceFactory<T, Req, Cfg> for T
354where
355    T: ServiceFactory<Req, Cfg>,
356{
357    #[inline]
358    fn into_factory(self) -> T {
359        self
360    }
361}
362
363pub mod dev {
364    pub use crate::and_then::{AndThen, AndThenFactory};
365    pub use crate::apply::{Apply, ApplyFactory};
366    pub use crate::chain::{ServiceChain, ServiceChainFactory};
367    pub use crate::fn_service::{
368        FnService, FnServiceConfig, FnServiceFactory, FnServiceNoConfig,
369    };
370    pub use crate::fn_shutdown::FnShutdown;
371    pub use crate::map::{Map, MapFactory};
372    pub use crate::map_config::{MapConfig, UnitConfig};
373    pub use crate::map_err::{MapErr, MapErrFactory};
374    pub use crate::map_init_err::MapInitErr;
375    pub use crate::middleware::ApplyMiddleware;
376    pub use crate::then::{Then, ThenFactory};
377}