From 8faf373a9962d1d91fac9f4114eba64a89670f49 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Mon, 20 Aug 2018 20:41:40 -0700 Subject: [PATCH] add .map_err() service combinator --- src/service.rs | 172 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) diff --git a/src/service.rs b/src/service.rs index f680d3c0..5d26b2b7 100644 --- a/src/service.rs +++ b/src/service.rs @@ -15,6 +15,11 @@ pub trait NewServiceExt: NewService { Error = Self::Error, InitError = Self::InitError, >; + + fn map_err(self, f: F) -> MapErrNewService + where + Self: Sized, + F: Fn(Self::Error) -> E; } impl NewServiceExt for T @@ -32,6 +37,13 @@ where { AndThenNewService::new(self, new_service) } + + fn map_err(self, f: F) -> MapErrNewService + where + F: Fn(Self::Error) -> E + { + MapErrNewService::new(self, f) + } } /// Trait for types that can be converted to a Service @@ -519,3 +531,163 @@ where } } } + +/// `MapErr` service combinator +pub struct MapErr { + a: A, + f: F, + e: marker::PhantomData, +} + +impl MapErr +where + A: Service, + F: Fn(A::Error) -> E, +{ + /// Create new `MapErr` combinator + pub fn new(a: A, f: F) -> Self { + Self { a, f, e: marker::PhantomData } + } +} + +impl Service for MapErr +where + A: Service, + F: Fn(A::Error) -> E + Clone, +{ + type Request = A::Request; + type Response = A::Response; + type Error = E; + type Future = MapErrFuture; + + fn poll_ready(&mut self) -> Poll<(), Self::Error> { + self.a.poll_ready().map_err(|e| (self.f)(e)) + } + + fn call(&mut self, req: Self::Request) -> Self::Future { + MapErrFuture::new(self.a.call(req), self.f.clone()) + } +} + +pub struct MapErrFuture +where + A: Service, + F: Fn(A::Error) -> E, +{ + f: F, + fut: A::Future, +} + +impl MapErrFuture +where + A: Service, + F: Fn(A::Error) -> E, +{ + fn new(fut: A::Future, f: F) -> Self { + MapErrFuture { f, fut } + } +} + +impl Future for MapErrFuture +where + A: Service, + F: Fn(A::Error) -> E, +{ + type Item = A::Response; + type Error = E; + + fn poll(&mut self) -> Poll { + self.fut.poll().map_err(|e| (self.f)(e)) + } +} + +/// `MapErrNewService` new service combinator +pub struct MapErrNewService { + a: A, + f: F, + e: marker::PhantomData, +} + +impl MapErrNewService +where + A: NewService, + F: Fn(A::Error) -> E, +{ + /// Create new `MapErr` new service instance + pub fn new(a: A, f: F) -> Self { + Self { a, f, e: marker::PhantomData } + } +} + +impl NewService for MapErrNewService +where + A: NewService + Clone, + F: Fn(A::Error) -> E + Clone, +{ + type Request = A::Request; + type Response = A::Response; + type Error = E; + type Service = MapErr; + + type InitError = A::InitError; + type Future = MapErrNewServiceFuture; + + fn new_service(&self) -> Self::Future { + MapErrNewServiceFuture::new(self.a.new_service(), self.f.clone()) + } +} + +impl Clone for MapErrNewService +where + A: NewService + Clone, + F: Fn(A::Error) -> E + Clone, +{ + fn clone(&self) -> Self { + Self { + a: self.a.clone(), + f: self.f.clone(), + e: marker::PhantomData, + } + } +} + +pub struct MapErrNewServiceFuture +where + A: NewService, + F: Fn(A::Error) -> E, +{ + fut: A::Future, + a: Option, + f: F, +} + +impl MapErrNewServiceFuture +where + A: NewService, + F: Fn(A::Error) -> E, +{ + fn new(fut: A::Future, f: F) -> Self { + MapErrNewServiceFuture { + f, + fut, + a: None, + } + } +} + +impl Future for MapErrNewServiceFuture +where + A: NewService, + F: Fn(A::Error) -> E + Clone, +{ + type Item = MapErr; + type Error = A::InitError; + + fn poll(&mut self) -> Poll { + if let Async::Ready(service) = self.fut.poll()? { + Ok(Async::Ready(MapErr::new(service, self.f.clone()))) + } else { + Ok(Async::NotReady) + } + } +} \ No newline at end of file