1use std::{error, fmt, future::Future, io, pin::Pin, task::Context, task::Poll};
2
3use ntex_service::{Ctx, Service};
4
5#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
8pub enum Either<A, B> {
9 Left(A),
11 Right(B),
13}
14
15impl<A, B> Either<A, B> {
16 fn project(self: Pin<&mut Self>) -> Either<Pin<&mut A>, Pin<&mut B>> {
17 unsafe {
18 match self.get_unchecked_mut() {
19 Either::Left(a) => Either::Left(Pin::new_unchecked(a)),
20 Either::Right(b) => Either::Right(Pin::new_unchecked(b)),
21 }
22 }
23 }
24
25 #[inline]
26 pub fn is_left(&self) -> bool {
28 match *self {
29 Either::Left(_) => true,
30 Either::Right(_) => false,
31 }
32 }
33
34 #[inline]
35 pub fn is_right(&self) -> bool {
37 !self.is_left()
38 }
39
40 #[inline]
41 pub fn left(self) -> Option<A> {
43 match self {
44 Either::Left(l) => Some(l),
45 Either::Right(_) => None,
46 }
47 }
48
49 #[inline]
50 pub fn right(self) -> Option<B> {
52 match self {
53 Either::Left(_) => None,
54 Either::Right(r) => Some(r),
55 }
56 }
57
58 #[inline]
59 pub fn as_ref(&self) -> Either<&A, &B> {
61 match *self {
62 Either::Left(ref inner) => Either::Left(inner),
63 Either::Right(ref inner) => Either::Right(inner),
64 }
65 }
66
67 #[inline]
68 pub fn as_mut(&mut self) -> Either<&mut A, &mut B> {
70 match *self {
71 Either::Left(ref mut inner) => Either::Left(inner),
72 Either::Right(ref mut inner) => Either::Right(inner),
73 }
74 }
75}
76
77impl<T> Either<T, T> {
78 #[inline]
79 pub fn into_inner(self) -> T {
81 match self {
82 Either::Left(x) | Either::Right(x) => x,
83 }
84 }
85}
86
87impl<A, B> error::Error for Either<A, B>
89where
90 A: error::Error,
91 B: error::Error,
92{
93 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
94 match self {
95 Either::Left(a) => a.source(),
96 Either::Right(b) => b.source(),
97 }
98 }
99}
100
101impl<A, B> fmt::Display for Either<A, B>
102where
103 A: fmt::Display,
104 B: fmt::Display,
105{
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 match self {
108 Either::Left(a) => a.fmt(f),
109 Either::Right(b) => b.fmt(f),
110 }
111 }
112}
113
114impl<A, B> Future for Either<A, B>
115where
116 A: Future,
117 B: Future<Output = A::Output>,
118{
119 type Output = A::Output;
120
121 #[inline]
122 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
123 match self.project() {
124 Either::Left(x) => x.poll(cx),
125 Either::Right(x) => x.poll(cx),
126 }
127 }
128}
129
130impl<E: error::Error> From<Either<E, io::Error>> for io::Error {
131 fn from(err: Either<E, io::Error>) -> Self {
132 match err {
133 Either::Left(e) => io::Error::other(format!("{e:?}")),
134 Either::Right(e) => e,
135 }
136 }
137}
138
139impl<A, B, St, Req> Service<St, Req> for Either<A, B>
140where
141 A: Service<St, Req>,
142 B: Service<St, Req, Res = A::Res, Error = A::Error>,
143{
144 type Res = A::Res;
145 type Error = A::Error;
146
147 async fn call(&self, req: Req, ctx: Ctx<'_, Self, St>) -> Result<Self::Res, Self::Error> {
148 match self {
149 Either::Left(svc) => ctx.call(svc, req).await,
150 Either::Right(svc) => ctx.call(svc, req).await,
151 }
152 }
153
154 async fn ready(&self, ctx: Ctx<'_, Self, St>) -> Result<(), Self::Error> {
155 match self {
156 Either::Left(svc) => ctx.ready(svc).await,
157 Either::Right(svc) => ctx.ready(svc).await,
158 }
159 }
160
161 async fn shutdown(&self, ctx: Ctx<'_, Self, St>) {
162 match self {
163 Either::Left(svc) => ctx.shutdown(svc).await,
164 Either::Right(svc) => ctx.shutdown(svc).await,
165 }
166 }
167}
168
169#[cfg(test)]
170mod test {
171 use super::*;
172
173 #[test]
174 #[allow(clippy::unit_cmp)]
175 fn either() {
176 let mut e = Either::<(), ()>::Left(());
177 assert!(e.is_left());
178 assert!(!e.is_right());
179 assert!(e.left().is_some());
180 assert!(e.right().is_none());
181 e.as_ref();
182 e.as_mut();
183
184 let mut e = Either::<(), ()>::Right(());
185 assert!(!e.is_left());
186 assert!(e.is_right());
187 assert!(e.left().is_none());
188 assert!(e.right().is_some());
189 e.as_ref();
190 e.as_mut();
191
192 assert_eq!(Either::<(), ()>::Left(()).into_inner(), ());
193 assert_eq!(Either::<(), ()>::Right(()).into_inner(), ());
194
195 assert_eq!(
196 format!("{}", Either::<_, &'static str>::Left("test")),
197 "test"
198 );
199 assert_eq!(
200 format!("{}", Either::<&'static str, _>::Right("test")),
201 "test"
202 );
203 }
204}