mirror of
https://github.com/fafhrd91/actix-net
synced 2025-01-31 23:10:07 +01:00
150 lines
4.1 KiB
Rust
150 lines
4.1 KiB
Rust
//! 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)
|
|
}
|
|
}
|
|
}
|