//! 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; 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, } impl ActixCompat { /// Wraps a `tower_service::Service` in a compatibility wrapper. pub fn new(inner: S) -> Self { ActixCompat { inner, _phantom: PhantomData, } } } /// Extension trait for wrapping a `tower_service::Service` instance for use as /// 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) } /// 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, U: ActixService, { f(self.into_actix_service()).into_tower_service() } } impl TowerServiceExt for S where S: TowerService + Sized {} impl ActixService for ActixCompat where S: TowerService, { type Request = R; type Response = S::Response; type Error = S::Error; type Future = S::Future; fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> { TowerService::poll_ready(&mut self.inner) } fn call(&mut self, req: Self::Request) -> Self::Future { TowerService::call(&mut self.inner, req) } } /// 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, } impl TowerCompat { /// Wraps an `actix_service::Service` in a compatibility wrapper. pub fn new(inner: S) -> Self { TowerCompat { inner } } } /// Extension trait for wrapping an `actix_service::Service` instance for use as /// 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) } /// 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, U: TowerService, { f(self.into_tower_service()).into_actix_service() } } impl ActixServiceExt for S where S: ActixService + Sized {} impl TowerService for TowerCompat where S: ActixService, { type Response = S::Response; type Error = S::Error; type Future = S::Future; fn poll_ready(&mut self) -> futures::Poll<(), Self::Error> { ActixService::poll_ready(&mut self.inner) } fn call(&mut self, req: S::Request) -> Self::Future { ActixService::call(&mut self.inner, req) } } #[cfg(test)] mod tests { mod tower_service_into_actix_service { use crate::TowerServiceExt; use actix_service::{Service as ActixService, ServiceExt, Transform}; use futures::{future::FutureResult, Async, Future, Poll}; use tower_service::Service as TowerService; #[test] fn random_service_returns_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()); } #[test] fn random_service_can_combine() { let mut s = RandomService.into_actix_service().map(|x| x + 1); assert_eq!(Ok(Async::Ready(())), s.poll_ready()); assert_eq!(Ok(Async::Ready(5)), s.call(()).poll()); } #[test] fn random_service_can_use_actix_middleware() { let mut s = RandomService.wrap_with_actix_middleware(DoMathTransform); assert_eq!(Ok(Async::Ready(())), s.poll_ready()); assert_eq!(Ok(Async::Ready(68)), s.call(()).poll()); } #[test] fn random_service_and_add_service_chained() { let s1 = RandomService.into_actix_service(); let s2 = AddOneService.into_actix_service(); let s3 = AddOneService.into_actix_service(); let mut s = s1.and_then(s2).and_then(s3); assert_eq!(Ok(Async::Ready(())), s.poll_ready()); assert_eq!(Ok(Async::Ready(6)), s.call(()).poll()); } #[test] fn random_service_and_add_service_and_ignoring_service_chained() { let s1 = RandomService.into_actix_service(); let s2 = AddOneService.into_actix_service(); let s3 = AddOneService.into_actix_service(); let s4 = RandomService.into_actix_service(); let mut s = s1.and_then(s2).and_then(s3).and_then(s4); assert_eq!(Ok(Async::Ready(())), s.poll_ready()); assert_eq!(Ok(Async::Ready(4)), s.call(()).poll()); } #[test] fn random_service_can_be_transformed_to_do_math() { let transform = DoMath; let mut s = transform .new_transform(RandomService.into_actix_service()) .wait() .unwrap(); assert_eq!(Ok(Async::Ready(())), s.poll_ready()); assert_eq!(Ok(Async::Ready(68)), s.call(()).poll()); } struct RandomService; impl TowerService for RandomService { type Response = u32; type Error = (); type Future = FutureResult; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, _req: R) -> Self::Future { futures::finished(4) } } struct AddOneService; impl TowerService for AddOneService { type Response = u32; type Error = (); type Future = FutureResult; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, req: u32) -> Self::Future { futures::finished(req + 1) } } struct DoMathTransform(S); impl ActixService for DoMathTransform where S: ActixService, S::Future: 'static, { type Request = S::Request; type Response = u32; type Error = S::Error; type Future = Box>; fn poll_ready(&mut self) -> 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 * 17); Box::new(fut) } } struct DoMath; impl Transform for DoMath where S: ActixService, S::Future: 'static, { type Request = S::Request; type Response = u32; type Error = S::Error; type Transform = DoMathTransform; type InitError = (); type Future = FutureResult; fn new_transform(&self, service: S) -> Self::Future { futures::finished(DoMathTransform(service)) } } } mod actix_service_into_tower_service { use crate::{ActixServiceExt, TowerServiceExt}; use actix_service::{Service as ActixService, ServiceExt}; use futures::{future::FutureResult, Async, Future, Poll}; use tower_service::Service as TowerService; #[test] fn random_service_returns_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()); } #[test] fn random_service_can_use_tower_middleware() { let mut s = AddOneService::wrap(RandomService.into_tower_service()).into_actix_service(); assert_eq!(Ok(Async::Ready(())), s.poll_ready()); assert_eq!(Ok(Async::Ready(5)), s.call(()).poll()); } #[test] fn do_math_service_can_use_tower_middleware() { let mut s = AddOneService::wrap(DoMathService.into_tower_service()).into_actix_service(); assert_eq!(Ok(Async::Ready(())), s.poll_ready()); assert_eq!(Ok(Async::Ready(188)), s.call(11).poll()); } #[test] fn random_service_and_add_service_and_ignoring_service_chained() { let s1 = RandomService.wrap_with_tower_middleware(AddOneService::wrap); let s2 = DoMathService.wrap_with_tower_middleware(AddOneService::wrap); let mut s = s1.and_then(s2); assert_eq!(Ok(Async::Ready(())), s.poll_ready()); assert_eq!(Ok(Async::Ready(86)), s.call(()).poll()); } struct RandomService; impl ActixService for RandomService { type Request = (); type Response = u32; type Error = (); type Future = FutureResult; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, _req: Self::Request) -> Self::Future { futures::finished(4) } } struct AddOneService { inner: S, } impl AddOneService { fn wrap(inner: S) -> Self { AddOneService { inner } } } impl TowerService for AddOneService where S: TowerService, S::Future: 'static, { type Response = u32; type Error = S::Error; type Future = Box>; fn poll_ready(&mut self) -> Poll<(), Self::Error> { self.inner.poll_ready() } fn call(&mut self, req: R) -> Self::Future { let fut = self.inner.call(req).map(|x| x + 1); Box::new(fut) } } struct DoMathService; impl ActixService for DoMathService { type Request = u32; type Response = u32; type Error = (); type Future = FutureResult; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, req: Self::Request) -> Self::Future { futures::finished(req * 17) } } } }