1use std::pin::Pin;
3use std::task::{Context, Poll};
4
5use scrappy_service::{Service, ServiceFactory};
6use futures::{future, ready, Future};
7
8pub struct EitherService<A, B> {
14 left: A,
15 right: B,
16}
17
18impl<A: Clone, B: Clone> Clone for EitherService<A, B> {
19 fn clone(&self) -> Self {
20 EitherService {
21 left: self.left.clone(),
22 right: self.right.clone(),
23 }
24 }
25}
26
27impl<A, B> Service for EitherService<A, B>
28where
29 A: Service,
30 B: Service<Response = A::Response, Error = A::Error>,
31{
32 type Request = either::Either<A::Request, B::Request>;
33 type Response = A::Response;
34 type Error = A::Error;
35 type Future = future::Either<A::Future, B::Future>;
36
37 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
38 let left = self.left.poll_ready(cx)?;
39 let right = self.right.poll_ready(cx)?;
40
41 if left.is_ready() && right.is_ready() {
42 Poll::Ready(Ok(()))
43 } else {
44 Poll::Pending
45 }
46 }
47
48 fn call(&mut self, req: either::Either<A::Request, B::Request>) -> Self::Future {
49 match req {
50 either::Either::Left(req) => future::Either::Left(self.left.call(req)),
51 either::Either::Right(req) => future::Either::Right(self.right.call(req)),
52 }
53 }
54}
55
56pub struct Either<A, B> {
58 left: A,
59 right: B,
60}
61
62impl<A, B> Either<A, B> {
63 pub fn new(left: A, right: B) -> Either<A, B>
64 where
65 A: ServiceFactory,
66 A::Config: Clone,
67 B: ServiceFactory<
68 Config = A::Config,
69 Response = A::Response,
70 Error = A::Error,
71 InitError = A::InitError,
72 >,
73 {
74 Either { left, right }
75 }
76}
77
78impl<A, B> ServiceFactory for Either<A, B>
79where
80 A: ServiceFactory,
81 A::Config: Clone,
82 B: ServiceFactory<
83 Config = A::Config,
84 Response = A::Response,
85 Error = A::Error,
86 InitError = A::InitError,
87 >,
88{
89 type Request = either::Either<A::Request, B::Request>;
90 type Response = A::Response;
91 type Error = A::Error;
92 type InitError = A::InitError;
93 type Config = A::Config;
94 type Service = EitherService<A::Service, B::Service>;
95 type Future = EitherNewService<A, B>;
96
97 fn new_service(&self, cfg: A::Config) -> Self::Future {
98 EitherNewService {
99 left: None,
100 right: None,
101 left_fut: self.left.new_service(cfg.clone()),
102 right_fut: self.right.new_service(cfg),
103 }
104 }
105}
106
107impl<A: Clone, B: Clone> Clone for Either<A, B> {
108 fn clone(&self) -> Self {
109 Self {
110 left: self.left.clone(),
111 right: self.right.clone(),
112 }
113 }
114}
115
116#[doc(hidden)]
117#[pin_project::pin_project]
118pub struct EitherNewService<A: ServiceFactory, B: ServiceFactory> {
119 left: Option<A::Service>,
120 right: Option<B::Service>,
121 #[pin]
122 left_fut: A::Future,
123 #[pin]
124 right_fut: B::Future,
125}
126
127impl<A, B> Future for EitherNewService<A, B>
128where
129 A: ServiceFactory,
130 B: ServiceFactory<Response = A::Response, Error = A::Error, InitError = A::InitError>,
131{
132 type Output = Result<EitherService<A::Service, B::Service>, A::InitError>;
133
134 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
135 let this = self.project();
136
137 if this.left.is_none() {
138 *this.left = Some(ready!(this.left_fut.poll(cx))?);
139 }
140 if this.right.is_none() {
141 *this.right = Some(ready!(this.right_fut.poll(cx))?);
142 }
143
144 if this.left.is_some() && this.right.is_some() {
145 Poll::Ready(Ok(EitherService {
146 left: this.left.take().unwrap(),
147 right: this.right.take().unwrap(),
148 }))
149 } else {
150 Poll::Pending
151 }
152 }
153}