//! Contains `Either` service and related types and functions. use actix_service::{IntoNewService, NewService, Service}; use futures::{future, try_ready, Async, Future, IntoFuture, Poll}; /// Combine two different service types into a single type. /// /// Both services must be of the same request, response, and error types. /// `EitherService` is useful for handling conditional branching in service /// middleware to different inner service types. pub struct EitherService<A, B> { left: A, right: B, } impl<A: Clone, B: Clone> Clone for EitherService<A, B> { fn clone(&self) -> Self { EitherService { left: self.left.clone(), right: self.right.clone(), } } } impl<A, B> Service for EitherService<A, B> where A: Service, B: Service<Response = A::Response, Error = A::Error>, { type Request = either::Either<A::Request, B::Request>; type Response = A::Response; type Error = A::Error; type Future = future::Either<A::Future, B::Future>; fn poll_ready(&mut self) -> Poll<(), Self::Error> { let left = self.left.poll_ready()?; let right = self.right.poll_ready()?; if left.is_ready() && right.is_ready() { Ok(Async::Ready(())) } else { Ok(Async::NotReady) } } fn call(&mut self, req: either::Either<A::Request, B::Request>) -> Self::Future { match req { either::Either::Left(req) => future::Either::A(self.left.call(req)), either::Either::Right(req) => future::Either::B(self.right.call(req)), } } } /// Combine two different new service types into a single service. pub struct Either<A, B> { left: A, right: B, } impl<A, B> Either<A, B> { pub fn new<F1, F2>(srv_a: F1, srv_b: F2) -> Either<A, B> where A: NewService, B: NewService< Config = A::Config, Response = A::Response, Error = A::Error, InitError = A::InitError, >, F1: IntoNewService<A>, F2: IntoNewService<B>, { Either { left: srv_a.into_new_service(), right: srv_b.into_new_service(), } } } impl<A, B> NewService for Either<A, B> where A: NewService, B: NewService< Config = A::Config, Response = A::Response, Error = A::Error, InitError = A::InitError, >, { type Request = either::Either<A::Request, B::Request>; type Response = A::Response; type Error = A::Error; type InitError = A::InitError; type Config = A::Config; type Service = EitherService<A::Service, B::Service>; type Future = EitherNewService<A, B>; fn new_service(&self, cfg: &A::Config) -> Self::Future { EitherNewService { left: None, right: None, left_fut: self.left.new_service(cfg), right_fut: self.right.new_service(cfg), } } } impl<A: Clone, B: Clone> Clone for Either<A, B> { fn clone(&self) -> Self { Self { left: self.left.clone(), right: self.right.clone(), } } } #[doc(hidden)] pub struct EitherNewService<A: NewService, B: NewService> { left: Option<A::Service>, right: Option<B::Service>, left_fut: <A::Future as IntoFuture>::Future, right_fut: <B::Future as IntoFuture>::Future, } impl<A, B> Future for EitherNewService<A, B> where A: NewService, B: NewService<Response = A::Response, Error = A::Error, InitError = A::InitError>, { type Item = EitherService<A::Service, B::Service>; type Error = A::InitError; fn poll(&mut self) -> Poll<Self::Item, Self::Error> { if self.left.is_none() { self.left = Some(try_ready!(self.left_fut.poll())); } if self.right.is_none() { self.right = Some(try_ready!(self.right_fut.poll())); } if self.left.is_some() && self.right.is_some() { Ok(Async::Ready(EitherService { left: self.left.take().unwrap(), right: self.right.take().unwrap(), })) } else { Ok(Async::NotReady) } } }