rama_core/combinators/
either.rs

1use std::fmt;
2use std::io::IoSlice;
3use std::pin::Pin;
4use std::task::{Context as TaskContext, Poll};
5use tokio::io::{AsyncRead, AsyncWrite, Error as IoError, ReadBuf, Result as IoResult};
6
7#[macro_export]
8#[doc(hidden)]
9/// Implement the `Either` type for the available number of type parameters,
10/// using the given macro to define each variant.
11macro_rules! __impl_either {
12    ($macro:ident) => {
13        $macro!(Either, A, B,);
14        $macro!(Either3, A, B, C,);
15        $macro!(Either4, A, B, C, D,);
16        $macro!(Either5, A, B, C, D, E,);
17        $macro!(Either6, A, B, C, D, E, F,);
18        $macro!(Either7, A, B, C, D, E, F, G,);
19        $macro!(Either8, A, B, C, D, E, F, G, H,);
20        $macro!(Either9, A, B, C, D, E, F, G, H, I,);
21    };
22}
23
24#[doc(inline)]
25pub use crate::__impl_either as impl_either;
26
27macro_rules! define_either {
28    ($id:ident, $($param:ident),+ $(,)?) => {
29        /// A type to allow you to use multiple types as a single type.
30        ///
31        /// and will delegate the functionality to the type that is wrapped in the `Either` type.
32        /// To keep it easy all wrapped types are expected to work with the same inputs and outputs.
33        ///
34        /// You can use [`crate::combinators::impl_either`] to
35        /// implement the `Either` type for the available number of type parameters
36        /// on your own Trait implementations.
37        pub enum $id<$($param),+> {
38            $(
39                /// one of the Either variants
40                $param($param),
41            )+
42        }
43
44        impl<$($param),+> Clone for $id<$($param),+>
45        where
46            $($param: Clone),+
47        {
48            fn clone(&self) -> Self {
49                match self {
50                    $(
51                        $id::$param(s) => $id::$param(s.clone()),
52                    )+
53                }
54            }
55        }
56
57        impl<$($param),+> fmt::Debug for $id<$($param),+>
58        where
59            $($param: fmt::Debug),+
60        {
61            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62                match self {
63                    $(
64                        $id::$param(s) => write!(f, "{:?}", s),
65                    )+
66                }
67            }
68        }
69
70        impl<$($param),+> fmt::Display for $id<$($param),+>
71        where
72            $($param: fmt::Display),+
73        {
74            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75                match self {
76                    $(
77                        $id::$param(s) => write!(f, "{}", s),
78                    )+
79                }
80            }
81        }
82
83
84        impl<$($param),+> $id<$($param),+> {
85            /// Convert `Pin<&mut Either<A, B>>` to `Either<Pin<&mut A>, Pin<&mut B>>`,
86            /// pinned projections of the inner variants.
87            fn as_pin_mut(self: Pin<&mut Self>) -> $id<$(Pin<&mut $param>),+> {
88                // SAFETY: `get_unchecked_mut` is fine because we don't move anything.
89                // We can use `new_unchecked` because the `inner` parts are guaranteed
90                // to be pinned, as they come from `self` which is pinned, and we never
91                // offer an unpinned `&mut A` or `&mut B` through `Pin<&mut Self>`. We
92                // also don't have an implementation of `Drop`, nor manual `Unpin`.
93                unsafe {
94                    match self.get_unchecked_mut() {
95                        $(
96                            Self::$param(inner) => $id::$param(Pin::new_unchecked(inner)),
97                        )+
98                    }
99                }
100            }
101        }
102
103        impl<$($param),+, Output> std::future::Future for $id<$($param),+>
104        where
105            $($param: std::future::Future<Output = Output>),+
106        {
107            type Output = Output;
108
109            fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
110                match self.as_pin_mut() {
111                    $(
112                        $id::$param(fut) => fut.poll(cx),
113                    )+
114                }
115            }
116        }
117    };
118}
119
120impl_either!(define_either);
121
122macro_rules! impl_iterator_either {
123    ($id:ident, $($param:ident),+ $(,)?) => {
124        impl<$($param),+, Item> Iterator for $id<$($param),+>
125        where
126            $($param: Iterator<Item = Item>),+,
127        {
128            type Item = Item;
129
130            fn next(&mut self) -> Option<Item> {
131                match self {
132                    $(
133                        $id::$param(iter) => iter.next(),
134                    )+
135                }
136            }
137
138            fn size_hint(&self) -> (usize, Option<usize>) {
139                match self {
140                    $(
141                        $id::$param(iter) => iter.size_hint(),
142                    )+
143                }
144            }
145        }
146    };
147}
148
149impl_either!(impl_iterator_either);
150
151macro_rules! impl_async_read_write_either {
152    ($id:ident, $($param:ident),+ $(,)?) => {
153        impl<$($param),+> AsyncRead for $id<$($param),+>
154        where
155            $($param: AsyncRead),+,
156        {
157            fn poll_read(
158                self: Pin<&mut Self>,
159                cx: &mut TaskContext<'_>,
160                buf: &mut ReadBuf<'_>,
161            ) -> Poll<IoResult<()>> {
162                match self.as_pin_mut() {
163                    $(
164                        $id::$param(reader) => reader.poll_read(cx, buf),
165                    )+
166                }
167            }
168        }
169
170        impl<$($param),+> AsyncWrite for $id<$($param),+>
171        where
172            $($param: AsyncWrite),+,
173        {
174            fn poll_write(
175                self: Pin<&mut Self>,
176                cx: &mut TaskContext<'_>,
177                buf: &[u8],
178            ) -> Poll<Result<usize, IoError>> {
179                match self.as_pin_mut() {
180                    $(
181                        $id::$param(writer) => writer.poll_write(cx, buf),
182                    )+
183                }
184            }
185
186            fn poll_flush(self: Pin<&mut Self>, cx: &mut TaskContext<'_>) -> Poll<Result<(), IoError>> {
187                match self.as_pin_mut() {
188                    $(
189                        $id::$param(writer) => writer.poll_flush(cx),
190                    )+
191                }
192            }
193
194            fn poll_shutdown(self: Pin<&mut Self>, cx: &mut TaskContext<'_>) -> Poll<Result<(), IoError>> {
195                match self.as_pin_mut() {
196                    $(
197                        $id::$param(writer) => writer.poll_shutdown(cx),
198                    )+
199                }
200            }
201
202            fn poll_write_vectored(
203                self: Pin<&mut Self>,
204                cx: &mut TaskContext<'_>,
205                bufs: &[IoSlice<'_>],
206            ) -> Poll<Result<usize, IoError>> {
207                match self.as_pin_mut() {
208                    $(
209                        $id::$param(writer) => writer.poll_write_vectored(cx, bufs),
210                    )+
211                }
212            }
213
214            fn is_write_vectored(&self) -> bool {
215                match self {
216                    $(
217                        $id::$param(writer) => writer.is_write_vectored(),
218                    )+
219                }
220            }
221        }
222    };
223}
224
225impl_either!(impl_async_read_write_either);