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)]
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 async fn call(&self, req: Req, ctx: Ctx<'_, Self, St>) -> Result<Self::Res, Self::Error> {
151 match self {
152 Either::Left(svc) => ctx.call(svc, req).await,
153 Either::Right(svc) => ctx.call(svc, req).await,
154 }
155 }
156
157 async fn ready(&self, ctx: Ctx<'_, Self, St>) -> Result<(), Self::Error> {
158 match self {
159 Either::Left(svc) => ctx.ready(svc).await,
160 Either::Right(svc) => ctx.ready(svc).await,
161 }
162 }
163
164 async fn shutdown(&self, ctx: Ctx<'_, Self, St>) {
165 match self {
166 Either::Left(svc) => ctx.shutdown(svc).await,
167 Either::Right(svc) => ctx.shutdown(svc).await,
168 }
169 }
170}
171
172#[cfg(test)]
173mod test {
174 use std::{cell::Cell, error::Error as _, future, rc::Rc};
175
176 use ntex_service::Pipeline;
177
178 use super::*;
179
180 #[test]
181 fn accessors() {
182 let mut value = Either::<u8, String>::Left(10);
183 assert!(value.is_left());
184 assert!(!value.is_right());
185 assert_eq!(value.as_ref(), Either::Left(&10));
186 if let Either::Left(inner) = value.as_mut() {
187 *inner = 20;
188 }
189 assert_eq!(value.left(), Some(20));
190
191 let mut value = Either::<u8, String>::Right("right".to_owned());
192 assert!(!value.is_left());
193 assert!(value.is_right());
194 assert_eq!(value.as_ref(), Either::Right(&"right".to_owned()));
195 if let Either::Right(inner) = value.as_mut() {
196 inner.push_str(" branch");
197 }
198 assert_eq!(value.right().as_deref(), Some("right branch"));
199
200 assert_eq!(Either::<u8, u8>::Left(1).into_inner(), 1);
201 assert_eq!(Either::<u8, u8>::Right(2).into_inner(), 2);
202
203 assert_eq!(
204 format!("{}", Either::<_, &'static str>::Left("test")),
205 "test"
206 );
207 assert_eq!(
208 format!("{}", Either::<&'static str, _>::Right("test")),
209 "test"
210 );
211 }
212
213 #[ntex::test]
214 async fn future() {
215 let left: Either<_, future::Ready<u8>> = Either::Left(future::ready(10));
216 assert_eq!(left.await, 10);
217
218 let right: Either<future::Ready<u8>, _> = Either::Right(future::ready(20));
219 assert_eq!(right.await, 20);
220 }
221
222 #[derive(Debug)]
223 struct TestError {
224 message: &'static str,
225 source: Option<io::Error>,
226 }
227
228 impl fmt::Display for TestError {
229 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230 f.write_str(self.message)
231 }
232 }
233
234 impl error::Error for TestError {
235 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
236 self.source
237 .as_ref()
238 .map(|source| source as &(dyn error::Error + 'static))
239 }
240 }
241
242 #[test]
243 fn errors() {
244 let left = Either::<TestError, TestError>::Left(TestError {
245 message: "left",
246 source: Some(io::Error::other("left source")),
247 });
248 assert_eq!(left.to_string(), "left");
249 assert_eq!(left.source().unwrap().to_string(), "left source");
250
251 let right = Either::<TestError, TestError>::Right(TestError {
252 message: "right",
253 source: Some(io::Error::other("right source")),
254 });
255 assert_eq!(right.to_string(), "right");
256 assert_eq!(right.source().unwrap().to_string(), "right source");
257
258 let left: io::Error = Either::<TestError, io::Error>::Left(TestError {
259 message: "converted",
260 source: None,
261 })
262 .into();
263 assert_eq!(left.kind(), io::ErrorKind::Other);
264 assert!(left.to_string().contains("converted"));
265
266 let right: io::Error = Either::<TestError, io::Error>::Right(io::Error::new(
267 io::ErrorKind::TimedOut,
268 "right error",
269 ))
270 .into();
271 assert_eq!(right.kind(), io::ErrorKind::TimedOut);
272 assert_eq!(right.to_string(), "right error");
273 }
274
275 #[derive(Default)]
276 struct ServiceState {
277 ready: Cell<bool>,
278 called: Cell<bool>,
279 shutdown: Cell<bool>,
280 }
281
282 struct TestService {
283 state: Rc<ServiceState>,
284 response: u8,
285 }
286
287 impl Service<(), u8> for TestService {
288 type Res = u8;
289 type Error = ();
290
291 async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Self::Error> {
292 self.state.ready.set(true);
293 Ok(())
294 }
295
296 async fn call(&self, req: u8, _: Ctx<'_, Self>) -> Result<Self::Res, Self::Error> {
297 self.state.called.set(true);
298 Ok(req + self.response)
299 }
300
301 async fn shutdown(&self, _: Ctx<'_, Self>) {
302 self.state.shutdown.set(true);
303 }
304 }
305
306 #[ntex::test]
307 async fn service() {
308 async fn check(service: Either<TestService, TestService>, response: u8) {
309 let state = match &service {
310 Either::Left(service) | Either::Right(service) => service.state.clone(),
311 };
312 let service = Pipeline::new((), service);
313
314 assert_eq!(service.ready().await, Ok(()));
315 assert!(state.ready.get());
316 assert_eq!(service.call(5).await, Ok(5 + response));
317 assert!(state.called.get());
318 service.shutdown().await;
319 assert!(state.shutdown.get());
320 }
321
322 let state = Rc::new(ServiceState::default());
323 check(
324 Either::Left(TestService {
325 state,
326 response: 10,
327 }),
328 10,
329 )
330 .await;
331
332 let state = Rc::new(ServiceState::default());
333 check(
334 Either::Right(TestService {
335 state,
336 response: 20,
337 }),
338 20,
339 )
340 .await;
341 }
342
343 #[test]
344 fn either_left_right() {
345 assert_eq!(Either::<u8, u8>::Left(1).left(), Some(1));
346 assert_eq!(Either::<u8, u8>::Left(1).right(), None);
347 assert_eq!(Either::<u8, u8>::Right(2).left(), None);
348 assert_eq!(Either::<u8, u8>::Right(2).right(), Some(2));
349 }
350}