diff --git a/src/service/map.rs b/src/service/map.rs new file mode 100644 index 00000000..865b2e23 --- /dev/null +++ b/src/service/map.rs @@ -0,0 +1,171 @@ +use std::marker; + +use futures::{Async, Future, Poll}; +use tower_service::{NewService, Service}; + +/// `Map` service combinator +pub struct Map { + a: A, + f: F, + r: marker::PhantomData, +} + +impl Map +where + A: Service, + F: Fn(A::Response) -> R, +{ + /// Create new `Map` combinator + pub fn new(a: A, f: F) -> Self { + Self { + a, + f, + r: marker::PhantomData, + } + } +} + +impl Service for Map +where + A: Service, + F: Fn(A::Response) -> R, + F: Clone, +{ + type Request = A::Request; + type Response = R; + type Error = A::Error; + type Future = MapFuture; + + fn poll_ready(&mut self) -> Poll<(), Self::Error> { + self.a.poll_ready() + } + + fn call(&mut self, req: Self::Request) -> Self::Future { + MapFuture::new(self.a.call(req), self.f.clone()) + } +} + +pub struct MapFuture +where + A: Service, + F: Fn(A::Response) -> R, +{ + f: F, + fut: A::Future, +} + +impl MapFuture +where + A: Service, + F: Fn(A::Response) -> R, +{ + fn new(fut: A::Future, f: F) -> Self { + MapFuture { f, fut } + } +} + +impl Future for MapFuture +where + A: Service, + F: Fn(A::Response) -> R, +{ + type Item = R; + type Error = A::Error; + + fn poll(&mut self) -> Poll { + match self.fut.poll()? { + Async::Ready(resp) => Ok(Async::Ready((self.f)(resp))), + Async::NotReady => Ok(Async::NotReady), + } + } +} + +/// `MapNewService` new service combinator +pub struct MapNewService { + a: A, + f: F, + r: marker::PhantomData, +} + +impl MapNewService +where + A: NewService, + F: Fn(A::Response) -> R, +{ + /// Create new `Map` new service instance + pub fn new(a: A, f: F) -> Self { + Self { + a, + f, + r: marker::PhantomData, + } + } +} + +impl Clone for MapNewService +where + A: NewService + Clone, + F: Fn(A::Response) -> R + Clone, +{ + fn clone(&self) -> Self { + Self { + a: self.a.clone(), + f: self.f.clone(), + r: marker::PhantomData, + } + } +} + +impl NewService for MapNewService +where + A: NewService, + F: Fn(A::Response) -> R + Clone, +{ + type Request = A::Request; + type Response = R; + type Error = A::Error; + type Service = Map; + + type InitError = A::InitError; + type Future = MapNewServiceFuture; + + fn new_service(&self) -> Self::Future { + MapNewServiceFuture::new(self.a.new_service(), self.f.clone()) + } +} + +pub struct MapNewServiceFuture +where + A: NewService, + F: Fn(A::Response) -> R, +{ + fut: A::Future, + f: Option, +} + +impl MapNewServiceFuture +where + A: NewService, + F: Fn(A::Response) -> R, +{ + fn new(fut: A::Future, f: F) -> Self { + MapNewServiceFuture { f: Some(f), fut } + } +} + +impl Future for MapNewServiceFuture +where + A: NewService, + F: Fn(A::Response) -> R, +{ + type Item = Map; + type Error = A::InitError; + + fn poll(&mut self) -> Poll { + if let Async::Ready(service) = self.fut.poll()? { + Ok(Async::Ready(Map::new(service, self.f.take().unwrap()))) + } else { + Ok(Async::NotReady) + } + } +} diff --git a/src/service/map_err.rs b/src/service/map_err.rs index a4bcf1e1..bf519980 100644 --- a/src/service/map_err.rs +++ b/src/service/map_err.rs @@ -115,7 +115,7 @@ where impl NewService for MapErrNewService where - A: NewService + Clone, + A: NewService, F: Fn(A::Error) -> E + Clone, { type Request = A::Request; diff --git a/src/service/mod.rs b/src/service/mod.rs index e5d1d537..c86d5a3a 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -4,12 +4,14 @@ use tower_service::{NewService, Service}; mod and_then; mod fn_service; mod fn_state_service; +mod map; mod map_err; mod map_init_err; pub use self::and_then::{AndThen, AndThenNewService}; pub use self::fn_service::FnService; pub use self::fn_state_service::FnStateService; +pub use self::map::{Map, MapNewService}; pub use self::map_err::{MapErr, MapErrNewService}; pub use self::map_init_err::MapInitErr; @@ -27,6 +29,14 @@ pub trait NewServiceExt: NewService { AndThenNewService::new(self, new_service) } + fn map(self, f: F) -> MapNewService + where + Self: Sized, + F: Fn(Self::Response) -> R, + { + MapNewService::new(self, f) + } + fn map_err(self, f: F) -> MapErrNewService where Self: Sized,