1 //! Contains [`Either`] and related types and functions. 2 //! 3 //! See [`Either`] documentation for more details. 4 5 use futures_core::ready; 6 use pin_project::pin_project; 7 use std::{ 8 future::Future, 9 pin::Pin, 10 task::{Context, Poll}, 11 }; 12 use tower_layer::Layer; 13 use tower_service::Service; 14 15 /// Combine two different service types into a single type. 16 /// 17 /// Both services must be of the same request, response, and error types. 18 /// [`Either`] is useful for handling conditional branching in service middleware 19 /// to different inner service types. 20 #[pin_project(project = EitherProj)] 21 #[derive(Clone, Debug)] 22 pub enum Either<A, B> { 23 /// One type of backing [`Service`]. 24 A(#[pin] A), 25 /// The other type of backing [`Service`]. 26 B(#[pin] B), 27 } 28 29 impl<A, B, Request> Service<Request> for Either<A, B> 30 where 31 A: Service<Request>, 32 A::Error: Into<crate::BoxError>, 33 B: Service<Request, Response = A::Response>, 34 B::Error: Into<crate::BoxError>, 35 { 36 type Response = A::Response; 37 type Error = crate::BoxError; 38 type Future = Either<A::Future, B::Future>; 39 poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>40 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { 41 use self::Either::*; 42 43 match self { 44 A(service) => Poll::Ready(Ok(ready!(service.poll_ready(cx)).map_err(Into::into)?)), 45 B(service) => Poll::Ready(Ok(ready!(service.poll_ready(cx)).map_err(Into::into)?)), 46 } 47 } 48 call(&mut self, request: Request) -> Self::Future49 fn call(&mut self, request: Request) -> Self::Future { 50 use self::Either::*; 51 52 match self { 53 A(service) => A(service.call(request)), 54 B(service) => B(service.call(request)), 55 } 56 } 57 } 58 59 impl<A, B, T, AE, BE> Future for Either<A, B> 60 where 61 A: Future<Output = Result<T, AE>>, 62 AE: Into<crate::BoxError>, 63 B: Future<Output = Result<T, BE>>, 64 BE: Into<crate::BoxError>, 65 { 66 type Output = Result<T, crate::BoxError>; 67 poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>68 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 69 match self.project() { 70 EitherProj::A(fut) => Poll::Ready(Ok(ready!(fut.poll(cx)).map_err(Into::into)?)), 71 EitherProj::B(fut) => Poll::Ready(Ok(ready!(fut.poll(cx)).map_err(Into::into)?)), 72 } 73 } 74 } 75 76 impl<S, A, B> Layer<S> for Either<A, B> 77 where 78 A: Layer<S>, 79 B: Layer<S>, 80 { 81 type Service = Either<A::Service, B::Service>; 82 layer(&self, inner: S) -> Self::Service83 fn layer(&self, inner: S) -> Self::Service { 84 match self { 85 Either::A(layer) => Either::A(layer.layer(inner)), 86 Either::B(layer) => Either::B(layer.layer(inner)), 87 } 88 } 89 } 90