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}