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