//! 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 { left: A, right: B, } impl Clone for EitherService { fn clone(&self) -> Self { EitherService { left: self.left.clone(), right: self.right.clone(), } } } impl Service for EitherService where A: Service, B: Service, { type Request = either::Either; type Response = A::Response; type Error = A::Error; type Future = future::Either; 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) -> 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 { left: A, right: B, } impl Either { pub fn new(srv_a: F1, srv_b: F2) -> Either where A: NewService, B: NewService< Config = A::Config, Response = A::Response, Error = A::Error, InitError = A::InitError, >, F1: IntoNewService, F2: IntoNewService, { Either { left: srv_a.into_new_service(), right: srv_b.into_new_service(), } } } impl NewService for Either where A: NewService, B: NewService< Config = A::Config, Response = A::Response, Error = A::Error, InitError = A::InitError, >, { type Request = either::Either; type Response = A::Response; type Error = A::Error; type InitError = A::InitError; type Config = A::Config; type Service = EitherService; type Future = EitherNewService; 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 Clone for Either { fn clone(&self) -> Self { Self { left: self.left.clone(), right: self.right.clone(), } } } #[doc(hidden)] pub struct EitherNewService { left: Option, right: Option, left_fut: ::Future, right_fut: ::Future, } impl Future for EitherNewService where A: NewService, B: NewService, { type Item = EitherService; type Error = A::InitError; fn poll(&mut self) -> Poll { 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) } } }