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 | |