| 1 | //! Contains [`Either`] and related types and functions. |
| 2 | //! |
| 3 | //! See [`Either`] documentation for more details. |
| 4 | |
| 5 | use pin_project_lite::pin_project; |
| 6 | use std::{ |
| 7 | future::Future, |
| 8 | pin::Pin, |
| 9 | task::{Context, Poll}, |
| 10 | }; |
| 11 | use tower_layer::Layer; |
| 12 | use tower_service::Service; |
| 13 | |
| 14 | /// Combine two different service types into a single type. |
| 15 | /// |
| 16 | /// Both services must be of the same request, response, and error types. |
| 17 | /// [`Either`] is useful for handling conditional branching in service middleware |
| 18 | /// to different inner service types. |
| 19 | #[derive (Clone, Copy, Debug)] |
| 20 | pub enum Either<A, B> { |
| 21 | #[allow (missing_docs)] |
| 22 | Left(A), |
| 23 | #[allow (missing_docs)] |
| 24 | Right(B), |
| 25 | } |
| 26 | |
| 27 | impl<A, B, Request> Service<Request> for Either<A, B> |
| 28 | where |
| 29 | A: Service<Request>, |
| 30 | B: Service<Request, Response = A::Response, Error = A::Error>, |
| 31 | { |
| 32 | type Response = A::Response; |
| 33 | type Error = A::Error; |
| 34 | type Future = EitherResponseFuture<A::Future, B::Future>; |
| 35 | |
| 36 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { |
| 37 | match self { |
| 38 | Either::Left(service) => service.poll_ready(cx), |
| 39 | Either::Right(service) => service.poll_ready(cx), |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | fn call(&mut self, request: Request) -> Self::Future { |
| 44 | match self { |
| 45 | Either::Left(service) => EitherResponseFuture { |
| 46 | kind: Kind::Left { |
| 47 | inner: service.call(request), |
| 48 | }, |
| 49 | }, |
| 50 | Either::Right(service) => EitherResponseFuture { |
| 51 | kind: Kind::Right { |
| 52 | inner: service.call(request), |
| 53 | }, |
| 54 | }, |
| 55 | } |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | pin_project! { |
| 60 | /// Response future for [`Either`]. |
| 61 | pub struct EitherResponseFuture<A, B> { |
| 62 | #[pin] |
| 63 | kind: Kind<A, B> |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | pin_project! { |
| 68 | #[project = KindProj] |
| 69 | enum Kind<A, B> { |
| 70 | Left { #[pin] inner: A }, |
| 71 | Right { #[pin] inner: B }, |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | impl<A, B> Future for EitherResponseFuture<A, B> |
| 76 | where |
| 77 | A: Future, |
| 78 | B: Future<Output = A::Output>, |
| 79 | { |
| 80 | type Output = A::Output; |
| 81 | |
| 82 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 83 | match self.project().kind.project() { |
| 84 | KindProj::Left { inner: Pin<&mut A> } => inner.poll(cx), |
| 85 | KindProj::Right { inner: Pin<&mut B> } => inner.poll(cx), |
| 86 | } |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | impl<S, A, B> Layer<S> for Either<A, B> |
| 91 | where |
| 92 | A: Layer<S>, |
| 93 | B: Layer<S>, |
| 94 | { |
| 95 | type Service = Either<A::Service, B::Service>; |
| 96 | |
| 97 | fn layer(&self, inner: S) -> Self::Service { |
| 98 | match self { |
| 99 | Either::Left(layer: &A) => Either::Left(layer.layer(inner)), |
| 100 | Either::Right(layer: &B) => Either::Right(layer.layer(inner)), |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | |