use futures::{Async, Future, Poll}; use super::{NewService, NewTransform, Service, Transform}; use crate::cell::Cell; /// `Apply` service combinator pub struct AndThenTransform where A: Service, B: Service, T: Transform, T::Error: From, { a: A, b: Cell, t: Cell, } impl AndThenTransform where A: Service, B: Service, T: Transform, T::Error: From, { /// Create new `Apply` combinator pub fn new(t: T, a: A, b: B) -> Self { Self { a, b: Cell::new(b), t: Cell::new(t), } } } impl Clone for AndThenTransform where A: Service + Clone, B: Service, T: Transform, T::Error: From, { fn clone(&self) -> Self { AndThenTransform { a: self.a.clone(), b: self.b.clone(), t: self.t.clone(), } } } impl Service for AndThenTransform where A: Service, B: Service, T: Transform, T::Error: From, { type Request = A::Request; type Response = T::Response; type Error = T::Error; type Future = AndThenTransformFuture; fn poll_ready(&mut self) -> Poll<(), Self::Error> { let notready = Async::NotReady == self.a.poll_ready()?; let notready = Async::NotReady == self.b.get_mut().poll_ready()? || notready; let notready = Async::NotReady == self.t.get_mut().poll_ready()? || notready; if notready { Ok(Async::NotReady) } else { Ok(Async::Ready(())) } } fn call(&mut self, req: A::Request) -> Self::Future { AndThenTransformFuture { b: self.b.clone(), t: self.t.clone(), fut_t: None, fut_a: Some(self.a.call(req)), } } } pub struct AndThenTransformFuture where A: Service, B: Service, T: Transform, T::Error: From, { b: Cell, t: Cell, fut_a: Option, fut_t: Option, } impl Future for AndThenTransformFuture where A: Service, B: Service, T: Transform, T::Error: From, { type Item = T::Response; type Error = T::Error; fn poll(&mut self) -> Poll { if let Some(ref mut fut) = self.fut_t { return fut.poll(); } match self.fut_a.as_mut().expect("Bug in actix-service").poll() { Ok(Async::Ready(resp)) => { let _ = self.fut_a.take(); self.fut_t = Some(self.t.get_mut().call(resp, self.b.get_mut())); self.poll() } Ok(Async::NotReady) => Ok(Async::NotReady), Err(err) => Err(err.into()), } } } /// `Apply` new service combinator pub struct AndThenTransformNewService { a: A, b: B, t: T, } impl AndThenTransformNewService where A: NewService, B: NewService, T: NewTransform, T::Error: From, { /// Create new `ApplyNewService` new service instance pub fn new(t: T, a: A, b: B) -> Self { Self { a, b, t } } } impl Clone for AndThenTransformNewService where A: Clone, B: Clone, T: Clone, { fn clone(&self) -> Self { Self { a: self.a.clone(), b: self.b.clone(), t: self.t.clone(), } } } impl NewService for AndThenTransformNewService where A: NewService, B: NewService, T: NewTransform, T::Error: From, { type Request = A::Request; type Response = T::Response; type Error = T::Error; type InitError = T::InitError; type Service = AndThenTransform; type Future = AndThenTransformNewServiceFuture; fn new_service(&self) -> Self::Future { AndThenTransformNewServiceFuture { a: None, b: None, t: None, fut_a: self.a.new_service(), fut_b: self.b.new_service(), fut_t: self.t.new_transform(), } } } pub struct AndThenTransformNewServiceFuture where A: NewService, B: NewService, T: NewTransform, T::Error: From, { fut_b: B::Future, fut_a: A::Future, fut_t: T::Future, a: Option, b: Option, t: Option, } impl Future for AndThenTransformNewServiceFuture where A: NewService, B: NewService, T: NewTransform, T::Error: From, { type Item = AndThenTransform; type Error = T::InitError; fn poll(&mut self) -> Poll { if self.t.is_none() { if let Async::Ready(transform) = self.fut_t.poll()? { self.t = Some(transform); } } if self.a.is_none() { if let Async::Ready(service) = self.fut_a.poll()? { self.a = Some(service); } } if self.b.is_none() { if let Async::Ready(service) = self.fut_b.poll()? { self.b = Some(service); } } if self.a.is_some() && self.b.is_some() && self.t.is_some() { Ok(Async::Ready(AndThenTransform { a: self.a.take().unwrap(), t: Cell::new(self.t.take().unwrap()), b: Cell::new(self.b.take().unwrap()), })) } else { Ok(Async::NotReady) } } } #[cfg(test)] mod tests { use futures::future::{ok, FutureResult}; use futures::{Async, Future, Poll}; use crate::{IntoNewService, IntoService, NewService, Service, ServiceExt}; #[derive(Clone)] struct Srv; impl Service for Srv { type Request = (); type Response = (); type Error = (); type Future = FutureResult<(), ()>; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, _: ()) -> Self::Future { ok(()) } } #[test] fn test_apply() { let blank = |req| Ok(req); let mut srv = blank.into_service().apply( |req: &'static str, srv: &mut Srv| srv.call(()).map(move |res| (req, res)), Srv, ); assert!(srv.poll_ready().is_ok()); let res = srv.call("srv").poll(); assert!(res.is_ok()); assert_eq!(res.unwrap(), Async::Ready(("srv", ()))); } #[test] fn test_new_service() { let blank = || Ok::<_, ()>((|req| Ok(req)).into_service()); let new_srv = blank.into_new_service().apply( |req: &'static str, srv: &mut Srv| srv.call(()).map(move |res| (req, res)), || Ok(Srv), ); if let Async::Ready(mut srv) = new_srv.new_service().poll().unwrap() { assert!(srv.poll_ready().is_ok()); let res = srv.call("srv").poll(); assert!(res.is_ok()); assert_eq!(res.unwrap(), Async::Ready(("srv", ()))); } else { panic!() } } }