diff --git a/actix-service/src/lib.rs b/actix-service/src/lib.rs index cc82bfa6..3db2bcc5 100644 --- a/actix-service/src/lib.rs +++ b/actix-service/src/lib.rs @@ -53,8 +53,14 @@ use self::ready::{err, ok, ready, Ready}; /// 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. +/// The `Service` trait just generalizes this form. Requests are defined as a generic type parameter +/// and responses and other details are defined as associated types on the trait impl. Notice that +/// this design means that services can receive many request types and converge them to a single +/// response type. +/// +/// Services can also have mutable state that influence computation by using a `Cell`, `RefCell` +/// or `Mutex`. Services intentionally do not take `&mut self` to reduce over-head in the +/// common cases. /// /// `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 @@ -64,8 +70,7 @@ use self::ready::{err, ok, ready, Ready}; /// ```ignore /// struct MyService; /// -/// impl Service for MyService { -/// type Request = u8; +/// impl Service for MyService { /// type Response = u64; /// type Error = MyError; /// type Future = Pin>>>; @@ -81,6 +86,9 @@ use self::ready::{err, ok, ready, Ready}; /// /// ```ignore /// async fn my_service(req: u8) -> Result; +/// +/// let svc = fn_service(my_service) +/// svc.call(123) /// ``` pub trait Service { /// Responses given by the service. @@ -144,7 +152,7 @@ pub trait ServiceFactory { /// Errors potentially raised while building a service. type InitError; - /// The future of the `Service` instance. + /// The future of the `Service` instance.g type Future: Future>; /// Create and return a new service asynchronously. diff --git a/actix-service/src/transform.rs b/actix-service/src/transform.rs index b0abe72b..8fdff66f 100644 --- a/actix-service/src/transform.rs +++ b/actix-service/src/transform.rs @@ -27,7 +27,7 @@ where /// Transform(middleware) wraps inner service and runs during inbound and/or outbound processing in /// the request/response lifecycle. It may modify request and/or response. /// -/// For example, timeout transform: +/// For example, a timeout service wrapper: /// /// ```ignore /// pub struct Timeout { @@ -35,11 +35,7 @@ where /// timeout: Duration, /// } /// -/// impl Service for Timeout -/// where -/// S: Service, -/// { -/// type Request = S::Request; +/// impl, Req> Service for Timeout { /// type Response = S::Response; /// type Error = TimeoutError; /// type Future = TimeoutServiceResponse; @@ -55,26 +51,22 @@ where /// } /// ``` /// -/// Timeout service in above example is decoupled from underlying service implementation and could -/// be applied to any service. +/// This wrapper service is decoupled from the underlying service implementation and could be +/// applied to any service. /// -/// The `Transform` trait defines the interface of a Service factory. `Transform` is often +/// The `Transform` trait defines the interface of a service wrapper. `Transform` is often /// implemented for middleware, defining how to construct a middleware Service. A Service that is /// constructed by the factory takes the Service that follows it during execution as a parameter, /// assuming ownership of the next Service. /// -/// Factory for `Timeout` middleware from the above example could look like this: +/// A transform for the `Timeout` middleware could look like this: /// /// ```ignore /// pub struct TimeoutTransform { /// timeout: Duration, /// } /// -/// impl Transform for TimeoutTransform -/// where -/// S: Service, -/// { -/// type Request = S::Request; +/// impl, Req> Transform for TimeoutTransform { /// type Response = S::Response; /// type Error = TimeoutError; /// type InitError = S::Error; @@ -82,7 +74,7 @@ where /// type Future = Ready>; /// /// fn new_transform(&self, service: S) -> Self::Future { -/// ready(Ok(TimeoutService { +/// ready(Ok(Timeout { /// service, /// timeout: self.timeout, /// })) @@ -227,3 +219,54 @@ where } } } + +#[cfg(test)] +mod tests { + use core::{ + future::{ready, Ready}, + time::Duration, + }; + + use super::*; + use crate::Service; + + // pseudo-doctest for Transform trait + pub struct TimeoutTransform { + timeout: Duration, + } + + // pseudo-doctest for Transform trait + impl, Req> Transform for TimeoutTransform { + type Response = S::Response; + type Error = S::Error; + type InitError = S::Error; + type Transform = Timeout; + type Future = Ready>; + + fn new_transform(&self, service: S) -> Self::Future { + ready(Ok(Timeout { + service, + _timeout: self.timeout, + })) + } + } + + // pseudo-doctest for Transform trait + pub struct Timeout { + service: S, + _timeout: Duration, + } + + // pseudo-doctest for Transform trait + impl, Req> Service for Timeout { + type Response = S::Response; + type Error = S::Error; + type Future = S::Future; + + crate::forward_ready!(service); + + fn call(&self, req: Req) -> Self::Future { + self.service.call(req) + } + } +}