From e0f4aac3b4cfbdb814c5f68a1530d60bad12a991 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Mon, 17 Sep 2018 18:10:23 -0700 Subject: [PATCH] add NewService::from_err combinator --- src/service/from_err.rs | 100 ++++++++++++++++++++++++++++++++++++++-- src/service/map_err.rs | 5 +- src/service/mod.rs | 15 +++++- 3 files changed, 115 insertions(+), 5 deletions(-) diff --git a/src/service/from_err.rs b/src/service/from_err.rs index 671046d7f..d0e40c58c 100644 --- a/src/service/from_err.rs +++ b/src/service/from_err.rs @@ -1,8 +1,8 @@ use std::marker::PhantomData; -use futures::{Future, Poll}; +use futures::{Async, Future, Poll}; -use super::Service; +use super::{NewService, Service}; /// Service for the `from_err` combinator, changing the error type of a service. /// @@ -77,12 +77,92 @@ where } } +/// NewService for the `from_err` combinator, changing the type of a new +/// service's error. +/// +/// This is created by the `NewServiceExt::from_err` method. +pub struct FromErrNewService { + a: A, + e: PhantomData, +} + +impl FromErrNewService +where + A: NewService, + E: From + From, +{ + /// Create new `FromErr` new service instance + pub fn new(a: A) -> Self { + Self { a, e: PhantomData } + } +} + +impl Clone for FromErrNewService +where + A: NewService + Clone, + E: From + From, +{ + fn clone(&self) -> Self { + Self { + a: self.a.clone(), + e: PhantomData, + } + } +} + +impl NewService for FromErrNewService +where + A: NewService, + E: From + From, +{ + type Request = A::Request; + type Response = A::Response; + type Error = E; + type Service = FromErr; + + type InitError = E; + type Future = FromErrNewServiceFuture; + + fn new_service(&self) -> Self::Future { + FromErrNewServiceFuture { + fut: self.a.new_service(), + e: PhantomData, + } + } +} + +pub struct FromErrNewServiceFuture +where + A: NewService, + E: From + From, +{ + fut: A::Future, + e: PhantomData, +} + +impl Future for FromErrNewServiceFuture +where + A: NewService, + E: From + From, +{ + type Item = FromErr; + type Error = E; + + fn poll(&mut self) -> Poll { + if let Async::Ready(service) = self.fut.poll()? { + Ok(Async::Ready(FromErr::new(service))) + } else { + Ok(Async::NotReady) + } + } +} + #[cfg(test)] mod tests { use futures::future::{err, FutureResult}; use super::*; - use service::{Service, ServiceExt}; + use service::{IntoNewService, NewServiceExt, Service, ServiceExt}; struct Srv; impl Service for Srv { @@ -124,4 +204,18 @@ mod tests { assert!(res.is_err()); assert_eq!(res.err().unwrap(), Error); } + + #[test] + fn test_new_service() { + let blank = || Ok::<_, ()>(Srv); + let new_srv = blank.into_new_service().from_err::(); + if let Async::Ready(mut srv) = new_srv.new_service().poll().unwrap() { + let res = srv.call(()).poll(); + assert!(res.is_err()); + assert_eq!(res.err().unwrap(), Error); + } else { + panic!() + } + } + } diff --git a/src/service/map_err.rs b/src/service/map_err.rs index ad7e20a50..d69bd143e 100644 --- a/src/service/map_err.rs +++ b/src/service/map_err.rs @@ -93,7 +93,10 @@ where } } -/// `MapErrNewService` new service combinator +/// NewService for the `map_err` combinator, changing the type of a new +/// service's error. +/// +/// This is created by the `NewServiceExt::map_err` method. pub struct MapErrNewService { a: A, f: F, diff --git a/src/service/mod.rs b/src/service/mod.rs index 57c3b5746..dbfb99f88 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -16,7 +16,7 @@ pub use self::and_then::{AndThen, AndThenNewService}; pub use self::apply::{Apply, ApplyNewService}; pub use self::fn_service::{FnNewService, FnService}; pub use self::fn_state_service::{FnStateNewService, FnStateService}; -pub use self::from_err::FromErr; +pub use self::from_err::{FromErr, FromErrNewService}; pub use self::map::{Map, MapNewService}; pub use self::map_err::{MapErr, MapErrNewService}; pub use self::map_init_err::MapInitErr; @@ -133,6 +133,19 @@ pub trait NewServiceExt: NewService { AndThenNewService::new(self, new_service) } + /// Map this service's error and new service's init error to any error + /// implementing `From` for this service`s `Error`. + /// + /// Note that this function consumes the receiving new service and returns a + /// wrapped version of it. + fn from_err(self) -> FromErrNewService + where + Self: Sized, + E: From + From, + { + FromErrNewService::new(self) + } + fn map(self, f: F) -> MapNewService where Self: Sized,