diff --git a/actix-tower/src/lib.rs b/actix-tower/src/lib.rs index 78311a90..891b5017 100644 --- a/actix-tower/src/lib.rs +++ b/actix-tower/src/lib.rs @@ -1,4 +1,60 @@ -//! Utilities to ease interoperability with services based on the `tower-service` crate. +//! Utilities to provide interoperability between services based on the +//! `actix-service` and `tower-service` crates. +//! +//! ## Example +//! +//! In the following example, we take a `RandomService`—which will always +//! return 4—and wraps it with a middleware that will always add 1 to the +//! result. This pattern can be further used to wrap services from either +//! `tower-service` or `actix-service` with middleware provided by the other. +//! +//! ``` +//! use actix_tower::ActixServiceExt; +//! # use futures::{Async, Future}; +//! use actix_service::Service; +//! +//! struct RandomService; +//! impl Service for RandomService { +//! // … +//! # type Request = (); +//! # type Response = u32; +//! # type Error = (); +//! # type Future = futures::future::FutureResult; +//! # +//! # fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> { +//! # Ok(Async::Ready(())) +//! # } +//! # +//! # fn call(&mut self, _req: Self::Request) -> Self::Future { +//! # futures::finished(4) +//! # } +//! } +//! +//! struct AddOneMiddleware(S); +//! impl tower_service::Service for AddOneMiddleware +//! where +//! S: tower_service::Service, +//! S::Future: 'static, +//! { +//! /// … +//! # type Response = u32; +//! # type Error = S::Error; +//! # type Future = Box>; +//! # +//! # fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> { +//! # self.0.poll_ready() +//! # } +//! # +//! # fn call(&mut self, req: R) -> Self::Future { +//! # let fut = self.0.call(req).map(|x| x + 1); +//! # Box::new(fut) +//! # } +//! } +//! +//! let mut s = RandomService.wrap_with_tower_middleware(AddOneMiddleware); +//! assert_eq!(Ok(Async::Ready(())), s.poll_ready()); +//! assert_eq!(Ok(Async::Ready(5)), s.call(()).poll()); +//! ``` use actix_service::Service as ActixService; use std::marker::PhantomData; @@ -6,6 +62,8 @@ use tower_service::Service as TowerService; /// Compatibility wrapper associating a `tower_service::Service` with a particular /// `Request` type, so that it can be used as an `actix_service::Service`. +/// +/// Generally created through convenience methods on the `TowerServiceExt` trait. pub struct ActixCompat { inner: S, _phantom: PhantomData, @@ -25,6 +83,32 @@ impl ActixCompat { /// an `actix_service::Service`. pub trait TowerServiceExt : TowerService + Sized { /// Wraps a `tower_service::Service` in a compatibility wrapper. + /// + /// ``` + /// use actix_service::Service; + /// use actix_tower::TowerServiceExt; + /// # use futures::{Async, Future}; + /// + /// struct RandomService; + /// impl tower_service::Service for RandomService { + /// // … + /// # type Response = u32; + /// # type Error = (); + /// # type Future = futures::future::FutureResult; + /// # + /// # fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> { + /// # Ok(Async::Ready(())) + /// # } + /// # + /// # fn call(&mut self, _req: R) -> Self::Future { + /// # futures::finished(4) + /// # } + /// } + /// + /// let mut s = RandomService.into_actix_service(); + /// assert_eq!(Ok(Async::Ready(())), s.poll_ready()); + /// assert_eq!(Ok(Async::Ready(4)), s.call(()).poll()); + /// ``` fn into_actix_service(self) -> ActixCompat { ActixCompat::new(self) } @@ -32,6 +116,54 @@ pub trait TowerServiceExt : TowerService + Sized { /// Takes a function that, when provided with an `actix_service::Service` wraps it /// and returns a new service. Useful for wrapping a `tower_service::Service` with /// middleware built for `actix_service`. + /// + /// ``` + /// use actix_tower::TowerServiceExt; + /// # use futures::{Async, Future}; + /// use tower_service::Service; + /// + /// struct RandomService; + /// impl Service for RandomService { + /// // … + /// # type Response = u32; + /// # type Error = (); + /// # type Future = futures::future::FutureResult; + /// # + /// # fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> { + /// # Ok(Async::Ready(())) + /// # } + /// # + /// # fn call(&mut self, _req: R) -> Self::Future { + /// # futures::finished(4) + /// # } + /// } + /// + /// struct AddOneTransform(S); + /// impl actix_service::Service for AddOneTransform + /// where + /// S: actix_service::Service, + /// S::Future: 'static, + /// { + /// /// … + /// # type Request = S::Request; + /// # type Response = u32; + /// # type Error = S::Error; + /// # type Future = Box>; + /// # + /// # fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> { + /// # self.0.poll_ready() + /// # } + /// # + /// # fn call(&mut self, req: Self::Request) -> Self::Future { + /// # let fut = self.0.call(req).map(|x| x + 1); + /// # Box::new(fut) + /// # } + /// } + /// + /// let mut s = RandomService.wrap_with_actix_middleware(AddOneTransform); + /// assert_eq!(Ok(Async::Ready(())), s.poll_ready()); + /// assert_eq!(Ok(Async::Ready(5)), s.call(()).poll()); + /// ``` fn wrap_with_actix_middleware(self, f: F) -> TowerCompat where F: FnOnce(ActixCompat) -> U, @@ -66,6 +198,8 @@ where /// Compatibility wrapper associating an `actix_service::Service` with a particular /// `Request` type, so that it can be used as a `tower_service::Service`. +/// +/// Generally created through convenience methods on the `ActixServiceExt` trait. pub struct TowerCompat { inner: S, } @@ -83,6 +217,33 @@ impl TowerCompat { /// a `tower_service::Service`. pub trait ActixServiceExt: ActixService + Sized { /// Wraps a `tower_service::Service` in a compatibility wrapper. + /// + /// ``` + /// use actix_tower::ActixServiceExt; + /// # use futures::{Async, Future}; + /// use tower_service::Service; + /// + /// struct RandomService; + /// impl actix_service::Service for RandomService { + /// // … + /// # type Request = (); + /// # type Response = u32; + /// # type Error = (); + /// # type Future = futures::future::FutureResult; + /// # + /// # fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> { + /// # Ok(Async::Ready(())) + /// # } + /// # + /// # fn call(&mut self, _req: Self::Request) -> Self::Future { + /// # futures::finished(4) + /// # } + /// } + /// + /// let mut s = RandomService.into_tower_service(); + /// assert_eq!(Ok(Async::Ready(())), s.poll_ready()); + /// assert_eq!(Ok(Async::Ready(4)), s.call(()).poll()); + /// ``` fn into_tower_service(self) -> TowerCompat { TowerCompat::new(self) } @@ -90,6 +251,54 @@ pub trait ActixServiceExt: ActixService + Sized { /// Takes a function that, when provided with a `tower_service::Service` wraps it /// and returns a new service. Useful for wrapping an `actix_service::Service` with /// middleware built for `tower_service`. + /// + /// ``` + /// use actix_tower::ActixServiceExt; + /// # use futures::{Async, Future}; + /// use actix_service::Service; + /// + /// struct RandomService; + /// impl Service for RandomService { + /// // … + /// # type Request = (); + /// # type Response = u32; + /// # type Error = (); + /// # type Future = futures::future::FutureResult; + /// # + /// # fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> { + /// # Ok(Async::Ready(())) + /// # } + /// # + /// # fn call(&mut self, _req: Self::Request) -> Self::Future { + /// # futures::finished(4) + /// # } + /// } + /// + /// struct AddOneMiddleware(S); + /// impl tower_service::Service for AddOneMiddleware + /// where + /// S: tower_service::Service, + /// S::Future: 'static, + /// { + /// /// … + /// # type Response = u32; + /// # type Error = S::Error; + /// # type Future = Box>; + /// # + /// # fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> { + /// # self.0.poll_ready() + /// # } + /// # + /// # fn call(&mut self, req: R) -> Self::Future { + /// # let fut = self.0.call(req).map(|x| x + 1); + /// # Box::new(fut) + /// # } + /// } + /// + /// let mut s = RandomService.wrap_with_tower_middleware(AddOneMiddleware); + /// assert_eq!(Ok(Async::Ready(())), s.poll_ready()); + /// assert_eq!(Ok(Async::Ready(5)), s.call(()).poll()); + /// ``` fn wrap_with_tower_middleware(self, f: F) -> ActixCompat where F: FnOnce(TowerCompat) -> U,