actix_service/lib.rs
1//! See [`Service`] docs for information on this crate's foundational trait.
2
3#![no_std]
4#![deny(rust_2018_idioms, nonstandard_style)]
5#![warn(future_incompatible, missing_docs)]
6#![allow(clippy::type_complexity)]
7#![doc(html_logo_url = "https://actix.rs/img/logo.png")]
8#![doc(html_favicon_url = "https://actix.rs/favicon.ico")]
9
10extern crate alloc;
11
12use alloc::{boxed::Box, rc::Rc, sync::Arc};
13use core::{
14 cell::RefCell,
15 future::Future,
16 task::{self, Context, Poll},
17};
18
19mod and_then;
20mod apply;
21mod apply_cfg;
22pub mod boxed;
23mod ext;
24mod fn_service;
25mod macros;
26mod map;
27mod map_config;
28mod map_err;
29mod map_init_err;
30mod pipeline;
31mod ready;
32mod then;
33mod transform;
34mod transform_err;
35
36pub use self::apply::{apply_fn, apply_fn_factory};
37pub use self::apply_cfg::{apply_cfg, apply_cfg_factory};
38pub use self::ext::{ServiceExt, ServiceFactoryExt, TransformExt};
39pub use self::fn_service::{fn_factory, fn_factory_with_config, fn_service};
40pub use self::map_config::{map_config, unit_config};
41pub use self::transform::{apply, ApplyTransform, Transform};
42
43#[allow(unused_imports)]
44use self::ready::{err, ok, ready, Ready};
45
46/// An asynchronous operation from `Request` to a `Response`.
47///
48/// The `Service` trait models a request/response interaction, receiving requests and returning
49/// replies. You can think about a service as a function with one argument that returns some result
50/// asynchronously. Conceptually, the operation looks like this:
51///
52/// ```ignore
53/// async fn(Request) -> Result<Response, Err>
54/// ```
55///
56/// The `Service` trait just generalizes this form. Requests are defined as a generic type parameter
57/// and responses and other details are defined as associated types on the trait impl. Notice that
58/// this design means that services can receive many request types and converge them to a single
59/// response type.
60///
61/// Services can also have mutable state that influence computation by using a `Cell`, `RefCell`
62/// or `Mutex`. Services intentionally do not take `&mut self` to reduce overhead in the
63/// common cases.
64///
65/// `Service` provides a symmetric and uniform API; the same abstractions can be used to represent
66/// both clients and servers. Services describe only _transformation_ operations which encourage
67/// simple API surfaces. This leads to simpler design of each service, improves test-ability and
68/// makes composition easier.
69///
70/// ```ignore
71/// struct MyService;
72///
73/// impl Service<u8> for MyService {
74/// type Response = u64;
75/// type Error = MyError;
76/// type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
77///
78/// fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ... }
79///
80/// fn call(&self, req: u8) -> Self::Future { ... }
81/// }
82/// ```
83///
84/// Sometimes it is not necessary to implement the Service trait. For example, the above service
85/// could be rewritten as a simple function and passed to [`fn_service`](fn_service()).
86///
87/// ```ignore
88/// async fn my_service(req: u8) -> Result<u64, MyError>;
89///
90/// let svc = fn_service(my_service)
91/// svc.call(123)
92/// ```
93pub trait Service<Req> {
94 /// Responses given by the service.
95 type Response;
96
97 /// Errors produced by the service when polling readiness or executing call.
98 type Error;
99
100 /// The future response value.
101 type Future: Future<Output = Result<Self::Response, Self::Error>>;
102
103 /// Returns `Ready` when the service is able to process requests.
104 ///
105 /// If the service is at capacity, then `Pending` is returned and the task is notified when the
106 /// service becomes ready again. This function is expected to be called while on a task.
107 ///
108 /// This is a best effort implementation. False positives are permitted. It is permitted for
109 /// the service to return `Ready` from a `poll_ready` call and the next invocation of `call`
110 /// results in an error.
111 ///
112 /// # Notes
113 /// 1. `poll_ready` might be called on a different task to `call`.
114 /// 1. In cases of chained services, `.poll_ready()` is called for all services at once.
115 fn poll_ready(&self, ctx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>;
116
117 /// Process the request and return the response asynchronously.
118 ///
119 /// This function is expected to be callable off-task. As such, implementations of `call` should
120 /// take care to not call `poll_ready`. If the service is at capacity and the request is unable
121 /// to be handled, the returned `Future` should resolve to an error.
122 ///
123 /// Invoking `call` without first invoking `poll_ready` is permitted. Implementations must be
124 /// resilient to this fact.
125 fn call(&self, req: Req) -> Self::Future;
126}
127
128/// Factory for creating `Service`s.
129///
130/// This is useful for cases where new `Service`s must be produced. One case is a TCP
131/// server listener: a listener accepts new connections, constructs a new `Service` for each using
132/// the `ServiceFactory` trait, and uses the new `Service` to process inbound requests on that new
133/// connection.
134///
135/// `Config` is a service factory configuration type.
136///
137/// Simple factories may be able to use [`fn_factory`] or [`fn_factory_with_config`] to
138/// reduce boilerplate.
139pub trait ServiceFactory<Req> {
140 /// Responses given by the created services.
141 type Response;
142
143 /// Errors produced by the created services.
144 type Error;
145
146 /// Service factory configuration.
147 type Config;
148
149 /// The kind of `Service` created by this factory.
150 type Service: Service<Req, Response = Self::Response, Error = Self::Error>;
151
152 /// Errors potentially raised while building a service.
153 type InitError;
154
155 /// The future of the `Service` instance.g
156 type Future: Future<Output = Result<Self::Service, Self::InitError>>;
157
158 /// Create and return a new service asynchronously.
159 fn new_service(&self, cfg: Self::Config) -> Self::Future;
160}
161
162// TODO: remove implement on mut reference.
163impl<'a, S, Req> Service<Req> for &'a mut S
164where
165 S: Service<Req> + 'a,
166{
167 type Response = S::Response;
168 type Error = S::Error;
169 type Future = S::Future;
170
171 fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
172 (**self).poll_ready(ctx)
173 }
174
175 fn call(&self, request: Req) -> S::Future {
176 (**self).call(request)
177 }
178}
179
180impl<'a, S, Req> Service<Req> for &'a S
181where
182 S: Service<Req> + 'a,
183{
184 type Response = S::Response;
185 type Error = S::Error;
186 type Future = S::Future;
187
188 fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
189 (**self).poll_ready(ctx)
190 }
191
192 fn call(&self, request: Req) -> S::Future {
193 (**self).call(request)
194 }
195}
196
197impl<S, Req> Service<Req> for Box<S>
198where
199 S: Service<Req> + ?Sized,
200{
201 type Response = S::Response;
202 type Error = S::Error;
203 type Future = S::Future;
204
205 fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), S::Error>> {
206 (**self).poll_ready(ctx)
207 }
208
209 fn call(&self, request: Req) -> S::Future {
210 (**self).call(request)
211 }
212}
213
214impl<S, Req> Service<Req> for Rc<S>
215where
216 S: Service<Req> + ?Sized,
217{
218 type Response = S::Response;
219 type Error = S::Error;
220 type Future = S::Future;
221
222 fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
223 (**self).poll_ready(ctx)
224 }
225
226 fn call(&self, request: Req) -> S::Future {
227 (**self).call(request)
228 }
229}
230
231/// This impl is deprecated since v2 because the `Service` trait now receives shared reference.
232impl<S, Req> Service<Req> for RefCell<S>
233where
234 S: Service<Req>,
235{
236 type Response = S::Response;
237 type Error = S::Error;
238 type Future = S::Future;
239
240 fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
241 self.borrow().poll_ready(ctx)
242 }
243
244 fn call(&self, request: Req) -> S::Future {
245 self.borrow().call(request)
246 }
247}
248
249impl<S, Req> ServiceFactory<Req> for Rc<S>
250where
251 S: ServiceFactory<Req>,
252{
253 type Response = S::Response;
254 type Error = S::Error;
255 type Config = S::Config;
256 type Service = S::Service;
257 type InitError = S::InitError;
258 type Future = S::Future;
259
260 fn new_service(&self, cfg: S::Config) -> S::Future {
261 self.as_ref().new_service(cfg)
262 }
263}
264
265impl<S, Req> ServiceFactory<Req> for Arc<S>
266where
267 S: ServiceFactory<Req>,
268{
269 type Response = S::Response;
270 type Error = S::Error;
271 type Config = S::Config;
272 type Service = S::Service;
273 type InitError = S::InitError;
274 type Future = S::Future;
275
276 fn new_service(&self, cfg: S::Config) -> S::Future {
277 self.as_ref().new_service(cfg)
278 }
279}
280
281/// Trait for types that can be converted to a `Service`
282pub trait IntoService<S, Req>
283where
284 S: Service<Req>,
285{
286 /// Convert to a `Service`
287 fn into_service(self) -> S;
288}
289
290/// Trait for types that can be converted to a `ServiceFactory`
291pub trait IntoServiceFactory<SF, Req>
292where
293 SF: ServiceFactory<Req>,
294{
295 /// Convert `Self` to a `ServiceFactory`
296 fn into_factory(self) -> SF;
297}
298
299impl<S, Req> IntoService<S, Req> for S
300where
301 S: Service<Req>,
302{
303 fn into_service(self) -> S {
304 self
305 }
306}
307
308impl<SF, Req> IntoServiceFactory<SF, Req> for SF
309where
310 SF: ServiceFactory<Req>,
311{
312 fn into_factory(self) -> SF {
313 self
314 }
315}
316
317/// Convert object of type `U` to a service `S`
318pub fn into_service<I, S, Req>(tp: I) -> S
319where
320 I: IntoService<S, Req>,
321 S: Service<Req>,
322{
323 tp.into_service()
324}