future_union/
lib.rs

1//! # Future Union
2//! When you use impl traits, specifically with futures,
3//! sometimes you will want to have a branching expression
4//! (e.g. an `if` or `match`) in which the different branches
5//! return different types that both impl Future. This does
6//! not work since in current stable rust impl trait can only
7//! refer to a single type.
8//!
9//! One solution to this problem is to use `futures::future::Either`
10//! to combine together all your different possible futures together
11//! into one type to return. Doing this by hand is really annoying
12//! and requires sweeping changes when you change the number of
13//! possible branches.
14//!
15//! This macro `future_union` does this automatically.
16//! Currently you still have to keep the total count per function, and then
17//! also the index (starting from 0). If those values are inaccurate then
18//! you'll get horrible type errors.
19//!
20//! ### Example
21//! ```no_run
22//! use futures::future::{self, Future};
23//! use future_union::future_union;
24//!
25//! fn impl_demo(n: usize) -> impl Future<Item=(), Error=()> {
26//!    match n {
27//!        0 => future_union!(3, 0, future::ok(())),
28//!        1 => future_union!(3, 1, future::ok(()).map(|_| ())),
29//!        _ => future_union!(3, 2, future::ok(()).map(|_| ()).map(|_| ())),
30//!    }
31//!}
32//! ```
33//!
34//! ### Future (heh) plans:
35//! - support for futures-0.3
36//! - implement a function attribute macro that detects `future_union` calls
37//!   in a given function and automatically adds the correct count and index e.g.:
38//!     ```ignore
39//!     use futures::future::Future;
40//!     #[future_union_fn]
41//!     fn impl_demo(n: usize) -> impl Future<Item=(), Error=()> {
42//!         match n {
43//!             0 => future_union_auto!(future::ok(())),
44//!             1 => future_union_auto!(future::ok(()).map(|_| ())),
45//!             _ => future_union_auto!(future::ok(()).map(|_| ()).map(|_| ())),
46//!         }
47//!     }
48//!     ```
49//! Contributions welcome!
50
51use proc_macro_hack::proc_macro_hack;
52
53#[proc_macro_hack]
54pub use future_union_impl::future_union_impl as future_union;
55
56#[cfg(test)]
57mod tests {
58    use futures::future;
59    use futures::future::Future;
60    use future_union;
61
62    #[test]
63    fn demo_compiles() {
64
65        fn _impl_demo(n: usize) -> impl Future<Item=(), Error=()> {
66            match n {
67                0 => future_union!(3, 0, future::ok(())),
68                1 => future_union!(3, 1, future::ok(()).map(|_| ())),
69                _ => future_union!(3, 2, future::ok(()).map(|_| ()).map(|_| ())),
70            }
71        }
72    }
73
74    #[test]
75    fn trees_as_expected() {
76        fn _tree_2() ->
77                     future::Either<
78                         [(); 0],
79                         [(); 1],
80                     > {
81            match 0 {
82                0 => future_union!(2, 0, [(); 0]),
83                _ => future_union!(2, 1, [(); 1]),
84            }
85        }
86
87        fn _tree_3() ->
88                     future::Either<
89                         future::Either<
90                             [(); 0],
91                             [(); 1],
92                         >,
93                         [(); 2],
94                     > {
95            match 0 {
96                0 => future_union!(3, 0, [(); 0]),
97                1 => future_union!(3, 1, [(); 1]),
98                _ => future_union!(3, 2, [(); 2]),
99            }
100        }
101
102        fn _tree_4() ->
103                     future::Either<
104                         future::Either<
105                             [(); 0],
106                             [(); 1],
107                         >,
108                         future::Either<
109                             [(); 2],
110                             [(); 3],
111                         >,
112                     > {
113            match 0 {
114                0 => future_union!(4, 0, [(); 0]),
115                1 => future_union!(4, 1, [(); 1]),
116                2 => future_union!(4, 2, [(); 2]),
117                _ => future_union!(4, 3, [(); 3]),
118            }
119        }
120
121        fn _tree_5() ->
122                     future::Either<
123                         future::Either<
124                             future::Either<
125                                 [(); 0],
126                                 [(); 1],
127                             >,
128                             future::Either<
129                                 [(); 2],
130                                 [(); 3],
131                             >,
132                         >,
133                         [(); 4]
134                     > {
135            match 0 {
136                0 => future_union!(5, 0, [(); 0]),
137                1 => future_union!(5, 1, [(); 1]),
138                2 => future_union!(5, 2, [(); 2]),
139                3 => future_union!(5, 3, [(); 3]),
140                _ => future_union!(5, 4, [(); 4]),
141            }
142        }
143
144        fn _tree_6() ->
145                     future::Either<
146                         future::Either<
147                             future::Either<
148                                 [(); 0],
149                                 [(); 1],
150                             >,
151                             future::Either<
152                                 [(); 2],
153                                 [(); 3],
154                             >,
155                         >,
156                         future::Either<
157                             [(); 4],
158                             [(); 5],
159                         >,
160                     > {
161            match 0 {
162                0 => future_union!(6, 0, [(); 0]),
163                1 => future_union!(6, 1, [(); 1]),
164                2 => future_union!(6, 2, [(); 2]),
165                3 => future_union!(6, 3, [(); 3]),
166                4 => future_union!(6, 4, [(); 4]),
167                _ => future_union!(6, 5, [(); 5]),
168            }
169        }
170
171        fn _tree_7() ->
172                     future::Either<
173                         future::Either<
174                             future::Either<
175                                 [(); 0],
176                                 [(); 1],
177                             >,
178                             future::Either<
179                                 [(); 2],
180                                 [(); 3],
181                             >,
182                         >,
183                         future::Either<
184                             future::Either<
185                                 [(); 4],
186                                 [(); 5],
187                             >,
188                             [(); 6],
189                         >,
190                     > {
191            match 0 {
192                0 => future_union!(7, 0, [(); 0]),
193                1 => future_union!(7, 1, [(); 1]),
194                2 => future_union!(7, 2, [(); 2]),
195                3 => future_union!(7, 3, [(); 3]),
196                4 => future_union!(7, 4, [(); 4]),
197                5 => future_union!(7, 5, [(); 5]),
198                _ => future_union!(7, 6, [(); 6]),
199            }
200        }
201
202        fn _tree_8() ->
203                     future::Either<
204                         future::Either<
205                             future::Either<
206                                 [(); 0],
207                                 [(); 1],
208                             >,
209                             future::Either<
210                                 [(); 2],
211                                 [(); 3],
212                             >,
213                         >, future::Either<
214                             future::Either<
215                                 [(); 4],
216                                 [(); 5],
217                             >,
218                             future::Either<
219                                 [(); 6],
220                                 [(); 7],
221                             >,
222                         >,
223                     > {
224            match 0 {
225                0 => future_union!(8, 0, [(); 0]),
226                1 => future_union!(8, 1, [(); 1]),
227                2 => future_union!(8, 2, [(); 2]),
228                3 => future_union!(8, 3, [(); 3]),
229                4 => future_union!(8, 4, [(); 4]),
230                5 => future_union!(8, 5, [(); 5]),
231                6 => future_union!(8, 6, [(); 6]),
232                _ => future_union!(8, 7, [(); 7]),
233            }
234        }
235
236        fn _tree_9() ->
237                     future::Either<
238                         future::Either<
239                             future::Either<
240                                 future::Either<
241                                     [(); 0],
242                                     [(); 1],
243                                 >,
244                                 future::Either<
245                                     [(); 2],
246                                     [(); 3],
247                                 >,
248                             >,
249                             future::Either<
250                                 future::Either<
251                                     [(); 4],
252                                     [(); 5],
253                                 >,
254                                 future::Either<
255                                     [(); 6],
256                                     [(); 7],
257                                 >,
258                             >,
259                         >,
260                         [(); 8],
261                     > {
262            match 0 {
263                0 => future_union!(9, 0, [(); 0]),
264                1 => future_union!(9, 1, [(); 1]),
265                2 => future_union!(9, 2, [(); 2]),
266                3 => future_union!(9, 3, [(); 3]),
267                4 => future_union!(9, 4, [(); 4]),
268                5 => future_union!(9, 5, [(); 5]),
269                6 => future_union!(9, 6, [(); 6]),
270                7 => future_union!(9, 7, [(); 7]),
271                _ => future_union!(9, 8, [(); 8]),
272            }
273        }
274    }
275}