//! See [`Service`] docs for information on this crate's foundational trait. #![no_std] #![deny(rust_2018_idioms, nonstandard_style)] #![allow(clippy::type_complexity)] #![doc(html_logo_url = "https://actix.rs/img/logo.png")] #![doc(html_favicon_url = "https://actix.rs/favicon.ico")] extern crate alloc; use alloc::{boxed::Box, rc::Rc, sync::Arc}; use core::{ cell::RefCell, future::Future, task::{self, Context, Poll}, }; mod and_then; mod apply; mod apply_cfg; pub mod boxed; mod ext; mod fn_service; mod map; mod map_config; mod map_err; mod map_init_err; mod pipeline; mod ready; mod then; mod transform; mod transform_err; pub use self::apply::{apply_fn, apply_fn_factory}; pub use self::apply_cfg::{apply_cfg, apply_cfg_factory}; pub use self::ext::{ServiceExt, ServiceFactoryExt}; pub use self::fn_service::{fn_factory, fn_factory_with_config, fn_service}; pub use self::map_config::{map_config, unit_config}; pub use self::pipeline::{pipeline, pipeline_factory, Pipeline, PipelineFactory}; pub use self::transform::{apply, Transform}; #[allow(unused_imports)] use self::ready::{err, ok, ready, Ready}; /// An asynchronous operation from `Request` to a `Response`. /// /// The `Service` trait models a request/response interaction, receiving requests and returning /// replies. You can think about a service as a function with one argument that returns some result /// asynchronously. Conceptually, the operation looks like this: /// /// ```ignore /// async fn(Request) -> Result /// ``` /// /// The `Service` trait just generalizes this form where each parameter is described as an /// associated type on the trait. Services can also have mutable state that influence computation. /// /// `Service` provides a symmetric and uniform API; the same abstractions can be used to represent /// both clients and servers. Services describe only _transformation_ operations which encourage /// simple API surfaces. This leads to simpler design of each service, improves test-ability and /// makes composition easier. /// /// ```ignore /// struct MyService; /// /// impl Service for MyService { /// type Request = u8; /// type Response = u64; /// type Error = MyError; /// type Future = Pin>>>; /// /// fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { ... } /// /// fn call(&self, req: Self::Request) -> Self::Future { ... } /// } /// ``` /// /// Sometimes it is not necessary to implement the Service trait. For example, the above service /// could be rewritten as a simple function and passed to [fn_service](fn_service()). /// /// ```ignore /// async fn my_service(req: u8) -> Result; /// ``` pub trait Service { /// Responses given by the service. type Response; /// Errors produced by the service when polling readiness or executing call. type Error; /// The future response value. type Future: Future>; /// Returns `Ready` when the service is able to process requests. /// /// If the service is at capacity, then `Pending` is returned and the task /// is notified when the service becomes ready again. This function is /// expected to be called while on a task. /// /// This is a **best effort** implementation. False positives are permitted. /// It is permitted for the service to return `Ready` from a `poll_ready` /// call and the next invocation of `call` results in an error. /// /// # Notes /// 1. `.poll_ready()` might be called on different task from actual service call. /// 1. In case of chained services, `.poll_ready()` get called for all services at once. fn poll_ready(&self, ctx: &mut task::Context<'_>) -> Poll>; /// Process the request and return the response asynchronously. /// /// This function is expected to be callable off task. As such, /// implementations should take care to not call `poll_ready`. If the /// service is at capacity and the request is unable to be handled, the /// returned `Future` should resolve to an error. /// /// Calling `call` without calling `poll_ready` is permitted. The /// implementation must be resilient to this fact. fn call(&self, req: Req) -> Self::Future; } /// Factory for creating `Service`s. /// /// Acts as a service factory. This is useful for cases where new `Service`s /// must be produced. One case is a TCP server listener. The listener /// accepts new TCP streams, obtains a new `Service` using the /// `ServiceFactory` trait, and uses the new `Service` to process inbound /// requests on that new TCP stream. /// /// `Config` is a service factory configuration type. pub trait ServiceFactory { /// Responses given by the created services. type Response; /// Errors produced by the created services. type Error; /// Service factory configuration. type Config; /// The kind of `Service` created by this factory. type Service: Service; /// Errors potentially raised while building a service. type InitError; /// The future of the `Service` instance. type Future: Future>; /// Create and return a new service asynchronously. fn new_service(&self, cfg: Self::Config) -> Self::Future; } impl<'a, S, Req> Service for &'a mut S where S: Service + 'a, { type Response = S::Response; type Error = S::Error; type Future = S::Future; fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll> { (**self).poll_ready(ctx) } fn call(&self, request: Req) -> S::Future { (**self).call(request) } } impl Service for Box where S: Service + ?Sized, { type Response = S::Response; type Error = S::Error; type Future = S::Future; fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll> { (**self).poll_ready(ctx) } fn call(&self, request: Req) -> S::Future { (**self).call(request) } } impl Service for RefCell where S: Service, { type Response = S::Response; type Error = S::Error; type Future = S::Future; fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll> { self.borrow().poll_ready(ctx) } fn call(&self, request: Req) -> S::Future { self.borrow().call(request) } } impl Service for Rc> where S: Service, { type Response = S::Response; type Error = S::Error; type Future = S::Future; fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll> { self.borrow().poll_ready(ctx) } fn call(&self, request: Req) -> S::Future { self.borrow().call(request) } } impl ServiceFactory for Rc where S: ServiceFactory, { type Response = S::Response; type Error = S::Error; type Config = S::Config; type Service = S::Service; type InitError = S::InitError; type Future = S::Future; fn new_service(&self, cfg: S::Config) -> S::Future { self.as_ref().new_service(cfg) } } impl ServiceFactory for Arc where S: ServiceFactory, { type Response = S::Response; type Error = S::Error; type Config = S::Config; type Service = S::Service; type InitError = S::InitError; type Future = S::Future; fn new_service(&self, cfg: S::Config) -> S::Future { self.as_ref().new_service(cfg) } } /// Trait for types that can be converted to a `Service` pub trait IntoService where S: Service, { /// Convert to a `Service` fn into_service(self) -> S; } /// Trait for types that can be converted to a `ServiceFactory` pub trait IntoServiceFactory where SF: ServiceFactory, { /// Convert `Self` to a `ServiceFactory` fn into_factory(self) -> SF; } impl IntoService for S where S: Service, { fn into_service(self) -> S { self } } impl IntoServiceFactory for SF where SF: ServiceFactory, { fn into_factory(self) -> SF { self } } /// Convert object of type `U` to a service `S` pub fn into_service(tp: I) -> S where I: IntoService, S: Service, { tp.into_service() } pub mod dev { pub use crate::apply::{Apply, ApplyFactory}; pub use crate::fn_service::{ FnService, FnServiceConfig, FnServiceFactory, FnServiceNoConfig, }; pub use crate::map::{Map, MapServiceFactory}; pub use crate::map_config::{MapConfig, UnitConfig}; pub use crate::map_err::{MapErr, MapErrServiceFactory}; pub use crate::map_init_err::MapInitErr; pub use crate::transform::ApplyTransform; pub use crate::transform_err::TransformMapInitErr; } #[macro_export] macro_rules! always_ready { () => { #[inline] fn poll_ready( &self, _: &mut ::core::task::Context<'_>, ) -> ::core::task::Poll> { Poll::Ready(Ok(())) } }; } #[macro_export] macro_rules! forward_ready { ($field:ident) => { #[inline] fn poll_ready( &self, cx: &mut ::core::task::Context<'_>, ) -> ::core::task::Poll> { self.$field .poll_ready(cx) .map_err(::core::convert::Into::into) } }; }