Skip to main content

ntex_util/future/
either.rs

1use std::{error, fmt, future::Future, io, pin::Pin, task::Context, task::Poll};
2
3use ntex_service::{Ctx, Service};
4
5/// A value of one of two types.
6///
7/// `Either` is a [`Future`] when both variants are futures with the same
8/// output, and a [`Service`] when both variants are services with the same
9/// request, response, and error types.
10#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
11pub enum Either<A, B> {
12    /// First branch of the type
13    Left(A),
14    /// Second branch of the type
15    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    /// Returns `true` if the value is the `Left` variant.
30    pub fn is_left(&self) -> bool {
31        match *self {
32            Either::Left(_) => true,
33            Either::Right(_) => false,
34        }
35    }
36
37    #[inline]
38    /// Returns `true` if the value is the `Right` variant.
39    pub fn is_right(&self) -> bool {
40        !self.is_left()
41    }
42
43    #[inline]
44    /// Converts the left side of `Either<A, B>` to an `Option<A>`.
45    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    /// Converts the right side of `Either<A, B>` to an `Option<B>`.
54    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    /// Converts `&Either<A, B>` to `Either<&A, &B>`.
63    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    /// Converts `&mut Either<A, B>` to `Either<&mut A, &mut B>`.
72    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    /// Extracts the value of an `Either` over two equal types.
83    pub fn into_inner(self) -> T {
84        match self {
85            Either::Left(x) | Either::Right(x) => x,
86        }
87    }
88}
89
90/// `Either` implements `Error` if *both* `A` and `B` implement it.
91impl<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}