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