1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/// Macro to implement custom `OneOf` type.
///
/// Example:
/// ```rust
/// use one_of_futures::impl_one_of;
///
/// impl_one_of!(MyEither;
///   Left,
///   Right
/// );
///
/// fn main() {
///   let either = match 1 {
///       0 => MyEither::Left(async { 1 }),
///       _ => MyEither::Right(async { 2 }),
///   };
/// }
/// ```
#[macro_export]
macro_rules! impl_one_of (
    ($enum_name:ident ; $head_variant:ident, $($tail_variants:ident),*) => {
        /// Combines multiple different futures, streams, or sinks having the
        /// same associated types into a single type.
        #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
        pub enum $enum_name<$head_variant, $( $tail_variants ),*> {
            $head_variant($head_variant),
            $( $tail_variants($tail_variants) ),*
        }

        impl<$head_variant, $($tail_variants),*> ::core::future::Future for
            $enum_name<$head_variant, $($tail_variants ),*>
            where
                $head_variant: ::core::future::Future,
                $( $tail_variants: ::core::future::Future<Output=$head_variant::Output> ),* {

            type Output = $head_variant::Output;

            fn poll(self: ::core::pin::Pin<&mut Self>, cx: &mut ::core::task::Context<'_>) ->::core::task::Poll<Self::Output> {
                unsafe {
                    match self.get_unchecked_mut() {
                        $enum_name::$head_variant(x) => ::core::pin::Pin::new_unchecked(x).poll(cx),
                        $(
                            $enum_name::$tail_variants(x) => ::core::pin::Pin::new_unchecked(x).poll(cx),
                        )*
                    }
                }
            }
        }

        impl<$head_variant, $($tail_variants),*> $crate::FusedFuture for
            $enum_name<$head_variant, $($tail_variants ),*>
            where
                $head_variant: $crate::FusedFuture,
                $( $tail_variants: $crate::FusedFuture<Output=$head_variant::Output> ),* {

            fn is_terminated(&self) -> bool {
                match self {
                    $enum_name::$head_variant(x) => x.is_terminated(),
                    $(
                        $enum_name::$tail_variants(x) => x.is_terminated(),
                    )*
                }
            }
        }

         impl<$head_variant, $($tail_variants),*> $crate::Stream for
            $enum_name<$head_variant, $($tail_variants ),*>
            where
                $head_variant: $crate::Stream,
                $( $tail_variants: $crate::Stream<Item=$head_variant::Item> ),* {

            type Item = $head_variant::Item;

            fn poll_next(self: ::core::pin::Pin<&mut Self>, cx: &mut ::core::task::Context<'_>) ->::core::task::Poll<Option<$head_variant::Item>> {
                unsafe {
                    match self.get_unchecked_mut() {
                        $enum_name::$head_variant(x) => ::core::pin::Pin::new_unchecked(x).poll_next(cx),
                        $(
                            $enum_name::$tail_variants(x) => ::core::pin::Pin::new_unchecked(x).poll_next(cx),
                        )*
                    }
                }
            }
        }

        impl<$head_variant, $($tail_variants),*> $crate::FusedStream for
            $enum_name<$head_variant, $( $tail_variants ),*>
            where
                $head_variant: $crate::FusedStream,
                $( $tail_variants: $crate::FusedStream<Item=$head_variant::Item> ),* {

            fn is_terminated(&self) -> bool {
                match self {
                    $enum_name::$head_variant(x) => x.is_terminated(),
                    $(
                        $enum_name::$tail_variants(x) => x.is_terminated(),
                    )*
                }
            }
        }

        #[cfg(feature = "sink")]
        impl<Item, $head_variant, $($tail_variants),*> futures_sink::Sink<Item> for
            $enum_name<$head_variant, $( $tail_variants ),*>
            where
                $head_variant: futures_sink::Sink<Item>,
                $( $tail_variants: futures_sink::Sink<Item, Error=$head_variant::Error> ),* {
            type Error = $head_variant::Error;

            fn poll_ready(self: ::core::pin::Pin<&mut Self>, cx: &mut ::core::task::Context<'_>) ->::core::task::Poll<Result<(), Self::Error>> {
                unsafe {
                    match self.get_unchecked_mut() {
                        $enum_name::$head_variant(x) => ::core::pin::Pin::new_unchecked(x).poll_ready(cx),
                        $(
                            $enum_name::$tail_variants(x) => ::core::pin::Pin::new_unchecked(x).poll_ready(cx),
                        )*
                    }
                }
            }

            fn start_send(self: ::core::pin::Pin<&mut Self>, item: Item) -> Result<(), Self::Error> {
                unsafe {
                    match self.get_unchecked_mut() {
                        $enum_name::$head_variant(x) => ::core::pin::Pin::new_unchecked(x).start_send(item),
                        $(
                            $enum_name::$tail_variants(x) => ::core::pin::Pin::new_unchecked(x).start_send(item),
                        )*
                    }
                }
            }

            fn poll_flush(self: ::core::pin::Pin<&mut Self>, cx: &mut ::core::task::Context<'_>) ->::core::task::Poll<Result<(), Self::Error>> {
                unsafe {
                    match self.get_unchecked_mut() {
                        $enum_name::$head_variant(x) => ::core::pin::Pin::new_unchecked(x).poll_flush(cx),
                        $(
                            $enum_name::$tail_variants(x) => ::core::pin::Pin::new_unchecked(x).poll_flush(cx),
                        )*
                    }
                }
            }

            fn poll_close(self: ::core::pin::Pin<&mut Self>, cx: &mut ::core::task::Context<'_>) ->::core::task::Poll<Result<(), Self::Error>> {
                unsafe {
                    match self.get_unchecked_mut() {
                        $enum_name::$head_variant(x) => ::core::pin::Pin::new_unchecked(x).poll_close(cx),
                        $(
                            $enum_name::$tail_variants(x) => ::core::pin::Pin::new_unchecked(x).poll_close(cx),
                        )*
                    }
                }
            }
        }
    }
);

impl_one_of!(OneOf8; One, Two, Three, Four, Five, Six, Seven, Eight);
impl_one_of!(OneOf7; One, Two, Three, Four, Five, Six, Seven);
impl_one_of!(OneOf6; One, Two, Three, Four, Five, Six);
impl_one_of!(OneOf5; One, Two, Three, Four, Five);
impl_one_of!(OneOf4; One, Two, Three, Four);
impl_one_of!(OneOf3; One, Two, Three);
impl_one_of!(OneOf2; One, Two);