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