1use std::{error, fmt, future::Future, io, pin::Pin, task::Context, task::Poll};
2
3use ntex_service::{BindCtx, Ctx, Service};
4
5#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
11pub enum Either<A, B> {
12 Left(A),
14 Right(B),
16}
17
18impl<A, B> Either<A, B> {
19 fn project(self: Pin<&mut Self>) -> Either<Pin<&mut A>, Pin<&mut B>> {
20 unsafe {
21 match self.get_unchecked_mut() {
22 Either::Left(a) => Either::Left(Pin::new_unchecked(a)),
23 Either::Right(b) => Either::Right(Pin::new_unchecked(b)),
24 }
25 }
26 }
27
28 #[inline]
29 pub fn is_left(&self) -> bool {
31 match *self {
32 Either::Left(_) => true,
33 Either::Right(_) => false,
34 }
35 }
36
37 #[inline]
38 pub fn is_right(&self) -> bool {
40 !self.is_left()
41 }
42
43 #[inline]
44 pub fn left(self) -> Option<A> {
46 match self {
47 Either::Left(l) => Some(l),
48 Either::Right(_) => None,
49 }
50 }
51
52 #[inline]
53 pub fn right(self) -> Option<B> {
55 match self {
56 Either::Left(_) => None,
57 Either::Right(r) => Some(r),
58 }
59 }
60
61 #[inline]
62 pub fn as_ref(&self) -> Either<&A, &B> {
64 match *self {
65 Either::Left(ref inner) => Either::Left(inner),
66 Either::Right(ref inner) => Either::Right(inner),
67 }
68 }
69
70 #[inline]
71 pub fn as_mut(&mut self) -> Either<&mut A, &mut B> {
73 match *self {
74 Either::Left(ref mut inner) => Either::Left(inner),
75 Either::Right(ref mut inner) => Either::Right(inner),
76 }
77 }
78}
79
80impl<T> Either<T, T> {
81 #[inline]
82 pub fn into_inner(self) -> T {
84 match self {
85 Either::Left(x) | Either::Right(x) => x,
86 }
87 }
88}
89
90impl<A, B> error::Error for Either<A, B>
92where
93 A: error::Error,
94 B: error::Error,
95{
96 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
97 match self {
98 Either::Left(a) => a.source(),
99 Either::Right(b) => b.source(),
100 }
101 }
102}
103
104impl<A, B> fmt::Display for Either<A, B>
105where
106 A: fmt::Display,
107 B: fmt::Display,
108{
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 match self {
111 Either::Left(a) => a.fmt(f),
112 Either::Right(b) => b.fmt(f),
113 }
114 }
115}
116
117impl<A, B> Future for Either<A, B>
118where
119 A: Future,
120 B: Future<Output = A::Output>,
121{
122 type Output = A::Output;
123
124 #[inline]
125 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
126 match self.project() {
127 Either::Left(x) => x.poll(cx),
128 Either::Right(x) => x.poll(cx),
129 }
130 }
131}
132
133impl<E: error::Error> From<Either<E, io::Error>> for io::Error {
134 fn from(err: Either<E, io::Error>) -> Self {
135 match err {
136 Either::Left(e) => io::Error::other(format!("{e:?}")),
137 Either::Right(e) => e,
138 }
139 }
140}
141
142impl<A, B, St, Req> Service<St, Req> for Either<A, B>
143where
144 A: Service<St, Req>,
145 B: Service<St, Req, Res = A::Res, Error = A::Error>,
146{
147 type Res = A::Res;
148 type Error = A::Error;
149
150 fn bind(&self, ctx: BindCtx<'_>) {
151 match self {
152 Either::Left(svc) => ctx.bind(svc),
153 Either::Right(svc) => ctx.bind(svc),
154 }
155 }
156
157 async fn call(&self, req: Req, ctx: Ctx<'_, Self, St>) -> Result<Self::Res, Self::Error> {
158 match self {
159 Either::Left(svc) => ctx.call(svc, req).await,
160 Either::Right(svc) => ctx.call(svc, req).await,
161 }
162 }
163
164 async fn ready(&self, ctx: Ctx<'_, Self, St>) -> Result<(), Self::Error> {
165 match self {
166 Either::Left(svc) => ctx.ready(svc).await,
167 Either::Right(svc) => ctx.ready(svc).await,
168 }
169 }
170
171 async fn shutdown(&self, ctx: Ctx<'_, Self, St>) {
172 match self {
173 Either::Left(svc) => ctx.shutdown(svc).await,
174 Either::Right(svc) => ctx.shutdown(svc).await,
175 }
176 }
177}
178
179#[cfg(test)]
180mod test {
181 use std::{cell::Cell, error::Error as _, future, rc::Rc};
182
183 use ntex_service::{Pipeline, ReadyBinding, ReadyNotifier};
184
185 use super::*;
186
187 #[test]
193 fn accessors() {
194 let mut value = Either::<u8, String>::Left(10);
195 assert!(value.is_left());
196 assert!(!value.is_right());
197 assert_eq!(value.as_ref(), Either::Left(&10));
198 if let Either::Left(inner) = value.as_mut() {
199 *inner = 20;
200 }
201 assert_eq!(value.left(), Some(20));
202
203 let mut value = Either::<u8, String>::Right("right".to_owned());
204 assert!(!value.is_left());
205 assert!(value.is_right());
206 assert_eq!(value.as_ref(), Either::Right(&"right".to_owned()));
207 if let Either::Right(inner) = value.as_mut() {
208 inner.push_str(" branch");
209 }
210 assert_eq!(value.right().as_deref(), Some("right branch"));
211
212 assert_eq!(Either::<u8, u8>::Left(1).into_inner(), 1);
213 assert_eq!(Either::<u8, u8>::Right(2).into_inner(), 2);
214
215 assert_eq!(
216 format!("{}", Either::<_, &'static str>::Left("test")),
217 "test"
218 );
219 assert_eq!(
220 format!("{}", Either::<&'static str, _>::Right("test")),
221 "test"
222 );
223 }
224
225 #[ntex::test]
230 async fn future() {
231 let left: Either<_, future::Ready<u8>> = Either::Left(future::ready(10));
232 assert_eq!(left.await, 10);
233
234 let right: Either<future::Ready<u8>, _> = Either::Right(future::ready(20));
235 assert_eq!(right.await, 20);
236 }
237
238 #[derive(Debug)]
239 struct TestError {
240 message: &'static str,
241 source: Option<io::Error>,
242 }
243
244 impl fmt::Display for TestError {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 f.write_str(self.message)
247 }
248 }
249
250 impl error::Error for TestError {
251 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
252 self.source
253 .as_ref()
254 .map(|source| source as &(dyn error::Error + 'static))
255 }
256 }
257
258 #[test]
264 fn errors() {
265 let left = Either::<TestError, TestError>::Left(TestError {
266 message: "left",
267 source: Some(io::Error::other("left source")),
268 });
269 assert_eq!(left.to_string(), "left");
270 assert_eq!(left.source().unwrap().to_string(), "left source");
271
272 let right = Either::<TestError, TestError>::Right(TestError {
273 message: "right",
274 source: Some(io::Error::other("right source")),
275 });
276 assert_eq!(right.to_string(), "right");
277 assert_eq!(right.source().unwrap().to_string(), "right source");
278
279 let left: io::Error = Either::<TestError, io::Error>::Left(TestError {
280 message: "converted",
281 source: None,
282 })
283 .into();
284 assert_eq!(left.kind(), io::ErrorKind::Other);
285 assert!(left.to_string().contains("converted"));
286
287 let right: io::Error = Either::<TestError, io::Error>::Right(io::Error::new(
288 io::ErrorKind::TimedOut,
289 "right error",
290 ))
291 .into();
292 assert_eq!(right.kind(), io::ErrorKind::TimedOut);
293 assert_eq!(right.to_string(), "right error");
294 }
295
296 #[derive(Default)]
297 struct ServiceState {
298 bound: Cell<bool>,
299 ready: Cell<bool>,
300 failed: Cell<bool>,
301 called: Cell<bool>,
302 shutdown: Cell<bool>,
303 changed: ReadyNotifier,
304 }
305
306 struct TestService {
307 state: Rc<ServiceState>,
308 response: u8,
309 }
310
311 impl Service<(), u8> for TestService {
312 type Res = u8;
313 type Error = ();
314
315 fn bind(&self, ctx: BindCtx<'_>) {
316 self.state.bound.set(true);
317 ctx.subscribe(&self.state.changed);
318 }
319
320 async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
321 self.state.ready.set(true);
322 if self.state.failed.get() { Err(()) } else { Ok(()) }
323 }
324
325 async fn call(&self, req: u8, _: Ctx<'_, Self>) -> Result<Self::Res, Self::Error> {
326 self.state.called.set(true);
327 Ok(req + self.response)
328 }
329
330 async fn shutdown(&self, _: Ctx<'_, Self>) {
331 self.state.shutdown.set(true);
332 }
333 }
334
335 #[ntex::test]
342 async fn service() {
343 async fn check(service: Either<TestService, TestService>, response: u8) {
344 let state = match &service {
345 Either::Left(service) | Either::Right(service) => service.state.clone(),
346 };
347 let service = Pipeline::new((), service);
348
349 assert!(state.bound.get());
350 assert_eq!(service.ready().await, Ok(()));
351 assert!(state.ready.get());
352 assert_eq!(service.call(5).await, Ok(5 + response));
353 assert!(state.called.get());
354
355 state.called.set(false);
356 state.failed.set(true);
357 state.changed.notify();
358 assert!(!service.is_ready());
359 assert_eq!(service.call(5).await, Err(()));
360 assert!(!state.called.get());
361 state.failed.set(false);
362 state.changed.notify();
363 assert_eq!(service.call(5).await, Ok(5 + response));
364
365 service.shutdown().await;
366 assert!(state.shutdown.get());
367 }
368
369 let state = Rc::new(ServiceState::default());
370 check(
371 Either::Left(TestService {
372 state,
373 response: 10,
374 }),
375 10,
376 )
377 .await;
378
379 let state = Rc::new(ServiceState::default());
380 check(
381 Either::Right(TestService {
382 state,
383 response: 20,
384 }),
385 20,
386 )
387 .await;
388 }
389
390 #[ntex::test]
396 async fn bound_service() {
397 for left in [true, false] {
398 let inner = ReadyBinding::new(TestService {
399 state: Rc::new(ServiceState::default()),
400 response: 10,
401 });
402 let service = if left {
403 Either::Left(inner)
404 } else {
405 Either::Right(inner)
406 };
407 let service = Pipeline::new((), service);
408 assert_eq!(service.ready().await, Ok(()));
409 assert_eq!(service.call(5).await, Ok(15));
410 }
411 }
412
413 #[test]
418 fn either_left_right() {
419 assert_eq!(Either::<u8, u8>::Left(1).left(), Some(1));
420 assert_eq!(Either::<u8, u8>::Left(1).right(), None);
421 assert_eq!(Either::<u8, u8>::Right(2).left(), None);
422 assert_eq!(Either::<u8, u8>::Right(2).right(), Some(2));
423 }
424}