Skip to main content

actix_utils/future/
either.rs

1//! A symmetric either future.
2
3use core::{
4    future::Future,
5    pin::Pin,
6    task::{Context, Poll},
7};
8
9use pin_project_lite::pin_project;
10
11pin_project! {
12    /// Combines two different futures that have the same output type.
13    ///
14    /// Construct variants with [`Either::left`] and [`Either::right`].
15    ///
16    /// # Examples
17    /// ```
18    /// use actix_utils::future::Either;
19    /// use core::future::{ready, Ready};
20    ///
21    /// # async fn run() {
22    /// let res = Either::<_, Ready<usize>>::left(ready(42));
23    /// assert_eq!(res.await, 42);
24    ///
25    /// let res = Either::<Ready<usize>, _>::right(ready(43));
26    /// assert_eq!(res.await, 43);
27    /// # }
28    /// ```
29    #[project = EitherProj]
30    #[derive(Debug, Clone)]
31    pub enum Either<L, R> {
32        /// A value of type `L`.
33        #[allow(missing_docs)]
34        Left { #[pin] value: L },
35
36        /// A value of type `R`.
37        #[allow(missing_docs)]
38        Right { #[pin] value: R },
39    }
40}
41
42impl<L, R> Either<L, R> {
43    /// Creates new `Either` using left variant.
44    #[inline]
45    pub fn left(value: L) -> Either<L, R> {
46        Either::Left { value }
47    }
48
49    /// Creates new `Either` using right variant.
50    #[inline]
51    pub fn right(value: R) -> Either<L, R> {
52        Either::Right { value }
53    }
54}
55
56impl<T> Either<T, T> {
57    /// Unwraps into inner value when left and right have a common type.
58    #[inline]
59    pub fn into_inner(self) -> T {
60        match self {
61            Either::Left { value } => value,
62            Either::Right { value } => value,
63        }
64    }
65}
66
67impl<L, R> Future for Either<L, R>
68where
69    L: Future,
70    R: Future<Output = L::Output>,
71{
72    type Output = L::Output;
73
74    #[inline]
75    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
76        match self.project() {
77            EitherProj::Left { value } => value.poll(cx),
78            EitherProj::Right { value } => value.poll(cx),
79        }
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use core::future::{ready, Ready};
86
87    use super::*;
88
89    #[actix_rt::test]
90    async fn test_either() {
91        let res = Either::<_, Ready<usize>>::left(ready(42));
92        assert_eq!(res.await, 42);
93
94        let res = Either::<Ready<usize>, _>::right(ready(43));
95        assert_eq!(res.await, 43);
96    }
97}