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}