1#[macro_export]
108macro_rules! chain {
109 ($function: ident($($params: expr),*)) => {
111 $function($($params),*)
112 };
113 (|$($c_params: ident),*| $body: block($($expr: expr),*)) => {
115 (|$($c_params),*| $body)($($expr),*)
116 };
117 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*)) => {
119 (|$($c_params),*| $body)($($expr),*)
120 };
121 (move |$($c_params: ident),*| $body: block($($expr: expr),*)) => {
123 (move |$($c_params),*| $body)($($expr),*)
124 };
125 ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*)) => {
127 (move |$($c_params),*| $body)($($expr),*)
128 };
129 (&|$($c_params: ident),*| $body: block($(*$expr: expr),*)) => {
131 (&|$($c_params),*| $body)($($expr),*)
132 };
133 ((&|$($c_params: ident),*| $body: expr)($($expr: expr),*)) => {
135 (&|$($c_params),*| $body)($($expr),*)
136 };
137 (& mut |$($c_params: ident),*| $body: block($($expr: expr),*)) => {
139 (& mut |$($c_params),*| $body)($($expr),*)
140 };
141 ((& mut |$($c_params: ident),*| $body: expr)($($expr: expr),*)) => {
143 (|$($c_params),*| $body)($($expr),*)
144 };
145 ($function: ident($($params: expr),*), $function2: ident) => {
147 $function2($function($($params),*))
148 };
149 ($function: ident($($params: expr),*), |$c_params: ident| $body: expr) => {
151 (|$c_params| $body)($function($($params),*))
152 };
153 ($function: ident($($params: expr),*), |$c_params: ident: $ty: ident| $body: expr) => {
155 (|$c_params: $ty| $body)($function($($params),*))
156 };
157 ($function: ident($($params: expr),*), |$c_params: ident: & $ty: ident| $body: expr) => {
159 (|$c_params: $ty| $body)($function($($params),*))
160 };
161 ($function: ident($($params: expr),*), |$c_params: ident: & mut $ty: ident| $body: tt) => {
163 (|$c_params: $ty| $body)($function($($params),*))
164 };
165 ($function: ident($($params: expr),*), move |$c_params: ident| $body: tt) => {
167 (move |$c_params| $body)($function($($params),*))
168 };
169 ($function: ident($($params: expr),*), move |$c_params: ident: $ty: ident| $body: tt) => {
171 (move |$c_params: $ty| $body)($function($($params),*))
172 };
173 ($function: ident($($params: expr),*), move |$c_params: ident: & $ty: ident| $body: tt) => {
175 (move |$c_params: $ty| $body)($function($($params),*))
176 };
177 ($function: ident($($params: expr),*), move |$c_params: ident: & mut $ty: ident| $body: tt) => {
179 (move |$c_params: $ty| $body)($function($($params),*))
180 };
181 ($function: ident($($params: expr),*), $function2: ident, $($more_func: ident),+) => {
183 chain!($function2($function($($params),*)), $($more_func),*)
184 };
185 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), $func: ident) => {
187 $func((|$($c_params),*| $body)($($expr),*))
188 };
189 ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), $func: ident) => {
191 $func((move |$($c_params),*| $body)($($expr),*))
192 };
193 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), |$($c2_params: ident),*| $body2: expr) => {
195 (|$($c2_params),*| $body2)((|$($c_params),*| $body)($($expr),*))
196 };
197 ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), |$c2_params: ident| $body2: expr) => {
199 (|$c2_params| $body2)((move |$($c_params),*| $body)($($expr),*))
200 };
201 ((|$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), $func: ident) => {
203 $func((|$($c_params: $ty),*| $body)($($expr),*))
204 };
205 ((move |$($c_params: ident: $ty: ty),*| $body: expr)($expr: expr), $func: ident) => {
207 $func((move |$($c_params: $ty),*| $body)($($expr),*))
208 };
209 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), |$c2_params: ident| $body2: expr) => {
211 (|$c2_params| $body2)((|$($c_params),*| $body)($($expr),*))
212 };
213 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), move |$c2_params: ident| $body2: expr) => {
215 (move |$c2_params| $body2)((|$($c_params),*| $body)($($expr),*))
216 };
217 ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), move |$c2_params: ident| $body2: expr) => {
219 (move |$c2_params| $body2)((move |$($c_params),*| $body)($($expr),*))
220 };
221 ((|$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), |$c2_params: ident| $body2: expr) => {
223 (|$c2_params| $body2)((|$($c_params: $ty),*| $body)($($expr),*))
224 };
225 ((move |$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), |$c2_params: ident| $body2: expr) => {
227 (|$c2_params| $body2)((move |$($c_params: $ty),*| $body)($($expr),*))
228 };
229 ((|$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), move |$c2_params: ident| $body2: expr) => {
231 (move |$c2_params| $body2)((|$($c_params: $ty),*| $body)($($expr),*))
232 };
233 ((move |$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), move |$c2_params: ident| $body2: expr) => {
235 (move |$c2_params| $body2)((move |$($c_params: $ty),*| $body)($($expr),*))
236 };
237 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), |$c2_params: ident: $ty: ty| $body2: expr) => {
239 (|$c2_params: $ty| $body2)((|$($c_params),*| $body)($($expr),*))
240 };
241 ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), |$c2_params: ident: $ty: ty| $body2: expr) => {
243 (|$c2_params: $ty| $body2)((move |$($c_params),*| $body)($($expr),*))
244 };
245 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), move |$c2_params: ident: $ty: ty| $body2: expr) => {
247 (move |$c2_params: $ty| $body2)((|$($c_params),*| $body)($($expr),*))
248 };
249 ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), move |$c2_params: ident: $ty: ty| $body2: expr) => {
251 (move |$c2_params: $ty| $body2)((move |$($c_params),*| $body)($($expr),*))
252 };
253 ((|$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), |$c2_params: ident: $ty2: ty| $body2: expr) => {
255 (|$c2_params: $ty2| $body2)((|$($c_params: $ty),*| $body)($($expr),*))
256 };
257 ((move |$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), |$c2_params: ident: $ty2: ty| $body2: expr) => {
259 (|$c2_params: $ty2| $body2)((move |$($c_params: $ty),*| $body)($($expr),*))
260 };
261 ((|$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), move |$c2_params: ident: $ty2: ty| $body2: expr) => {
263 (move |$c2_params: $ty2| $body2)((|$($c_params: $ty),*| $body)($($expr),*))
264 };
265 ((move |$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), move |$c2_params: ident: $ty2: ty| $body2: expr) => {
267 (move |$c2_params: $ty2| $body2)((move |$($c_params: $ty),*| $body)($($expr),*))
268 };
269 ($function: ident($($params: expr),*), |$c_params: ident| $body: expr, $($other: tt)*) => {
271 chain!((|$c_params| $body)($function($($params),*)), $($other)*)
272 };
273 ($function: ident($($params: expr),*), move |$c_params: ident| $body: expr, $($other: tt)*) => {
275 chain!((move |$c_params| $body)($function($($params),*)), $($other)*)
276 };
277 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), $function: ident, $($other: tt)*) => {
279 chain!($function((|$c_params| $body)($($expr),*)), $($other)*)
280 };
281 ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), $function: ident, $($other: tt)*) => {
283 chain!($function((move |$($c_params),*| $body)($($expr),*)), $($other)*)
284 };
285 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), |$($c2_params: ident),*| $body2: expr, $($other: tt)*) => {
287 chain!((|$($c_params),*| $body)($($expr),*), |$($c2_params),*| $body2)
288 };
289 ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), |$($c2_params: ident),*| $body2: expr, $($other: tt)*) => {
291 chain!((move |$($c_params),*| $body)($($expr),*), |$($c2_params),*| $body2)
292 };
293 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), move |$c2_params: ident| $body2: expr, $($other: tt)*) => {
295 chain!((move |$c2_params| $body2)((|$($c_params),*| $body)($($expr),*)), $($other)*)
296 };
297 ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), move |$($c2_params: ident),*| $body2: expr, $($other: tt)*) => {
299 chain!((move |$($c_params),*| $body)($($expr),*), move |$($c2_params),*| $body2)
300 };
301 ($function: ident($($params: expr),*), |$c_params: ident: $ty: ty| $body: expr, $($other: tt)*) => {
303 chain!((|$c_params: $ty| $body)($function($($params),*)), $($other)*)
304 };
305 ($function: ident($($params: expr),*), move |$c_params: ident: $ty: ty| $body: expr, $($other: tt)*) => {
307 chain!((move |$c_params: $ty| $body)($function($($params),*)), $($other)*)
308 };
309 ((|$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), $function: ident, $($other: tt)*) => {
311 chain!($function((|$($c_params: $ty),*| $body)($($expr),*)), $($other)*)
312 };
313 ((move |$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), $function: ident, $($other: tt)*) => {
315 chain!($function((|$c_params: $ty| $body)($($expr),*)), $($other)*)
316 };
317 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), |$c2_params: ident| $body2: expr, $($other: tt)*) => {
319 chain!((|$c2_params| $body2)((|$($c_params),*| $body)($($expr),*)), $(other)*)
320 };
321 ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), |$c2_params: ident| $body2: expr, $($other: tt)*) => {
323 chain!((|$c2_params| $body2)((move |$($c_params),*| $body)($($expr),*)), $(other)*)
324 };
325 ((|$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), |$c2_params: ident| $body2: expr, $($other: tt)*) => {
327 chain!((|$c2_params| $body2)((|$($c_params: $ty),*| $body)($($expr),*)), $($other)*)
328 };
329 ((move |$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), |$c2_params: ident| $body2: expr, $($other: tt)*) => {
331 chain!((|$c2_params| $body2)((move |$($c_params: $ty),*| $body)($($expr),*)), $($other)*)
332 };
333 ((|$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), move |$c2_params: ident| $body2: expr, $($other: tt)*) => {
335 chain!((move |$c2_params| $body2)((|$($c_params: $ty),*| $body)($($expr),*)), $($other)*)
336 };
337 ((move |$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), move |$c2_params: ident| $body2: expr, $($other: tt)*) => {
339 chain!((move |$c2_params| $body2)((move |$($c_params: $ty),*| $body)($($expr),*)), $($other)*)
340 };
341 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), |$c2_param: ident: $ty2: ty| $body2: expr, $($other: tt)*) => {
343 chain!((|$sc2_param : $ty2| $body2)((|$($c_params),*| $body)($($expr),*)), $($other)*)
344 };
345 ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), |$c2_param: ident: $ty2: ty| $body2: expr, $($other: tt)*) => {
347 chain!((|$sc2_param : $ty2| $body2)((move |$($c_params),*| $body)($($expr),*)), $($other)*)
348 };
349 ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), move |$c2_param: ident: $ty2: ty| $body2: expr, $($other: tt)*) => {
351 chain!((move |$sc2_param : $ty2| $body2)((|$($c_params),*| $body)($($expr),*)), $($other)*)
352 };
353 ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), move |$c2_param: ident: $ty2: ty| $body2: expr, $($other: tt)*) => {
355 chain!((move |$sc2_param : $ty2| $body2)((move |$($c_params),*| $body)($($expr),*)), $($other)*)
356 };
357 ((|$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), |$c2_param: ident: $ty2: ty| $body2: expr, $($other: tt)*) => {
359 chain!((|$c2_param : $ty2| $body2)((|$($c_params: $ty),*| $body)($($expr),*)), $($other)*)
360 };
361 ((move |$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), |$c2_param: ident: $ty2: ty| $body2: expr, $($other: tt)*) => {
363 chain!((|$sc2_param : $ty2| $body2)(move |$($c_params: $ty),*| $body)($($expr),*), $($other)*)
364 };
365 ((|$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), move |$c2_param: ident: $ty2: ty| $body2: expr, $($other: tt)*) => {
367 chain!((move |$sc2_param : $ty2| $body2)(|$($c_params: $ty),*| $body)($($expr),*), $($other)*)
368 };
369 ((move |$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), move |$c2_param: ident: $ty2: ty| $body2: expr, $($other: tt)*) => {
371 chain!((move |$sc2_param : $ty2| $body2)(move |$($c_params: $ty),*| $body)($($expr),*), $($other)*)
372 };
373}
374
375pub struct Chainable<R> {
381 val: R
382}
383
384impl<R> Chainable<R> {
385 pub fn chain<CR, F>(self, func: F) -> Chainable<CR> where F: FnOnce(R) -> CR {
388 Chainable {
389 val: func(self.val)
390 }
391 }
392
393 pub fn end(self) -> R {
395 self.val
396 }
397}
398
399impl<R> std::ops::Deref for Chainable<R> {
400 type Target = R;
401
402 fn deref(&self) -> &R {
403 &self.val
404 }
405}
406
407pub fn chain<R>(result: R) -> Chainable<R> {
435 Chainable { val: result }
436}
437
438#[cfg(test)]
439mod tests {
440 use super::*;
441 #[test]
442 fn func_chain() {
443 fn some_func(a: i64) -> i64 {
444 a
445 }
446 fn add_one(b: i64) -> i64 {
447 b + 1
448 }
449 assert_eq!(1.5f64, *chain(some_func(1)).chain(add_one).chain(add_one).chain(|c| (c as f64) / 2f64));
450 assert_eq!(10, *chain(some_func(1)).chain(add_one).chain(|c| c * 2).chain(|c| c * 2).chain(add_one).chain(add_one));
451 }
452
453 #[test]
454 fn func_chain_moved() {
455 fn some_func(a: i64) -> i64 {
456 a
457 }
458 fn add_one(b: i64) -> i64 {
459 b + 1
460 }
461 assert_eq!(10, *chain(some_func(1)).chain(add_one).chain(move |c| c * 2).chain(move |c| c * 2).chain(add_one).chain(add_one));
462 assert_eq!(10, *chain(some_func(1)).chain(add_one).chain(|c| c * 2).chain(move |c| c * 2).chain(add_one).chain(add_one));
463 assert_eq!(10, *chain(some_func(1)).chain(add_one).chain(move |c| c * 2).chain(|c| c * 2).chain(add_one).chain(add_one));
464 assert_eq!(14, *chain::<i64>((|a, b| a + b)(1i64, 1)).chain(add_one).chain(move |c| c * 2).chain(|c| c * 2).chain(add_one).chain(add_one));
465 assert_eq!(6.5f64, *chain::<i64>((|a, b| a + b)(1i64, 1)).chain(add_one).chain(move |c| c * 2).chain(|c| c * 2).chain(add_one).chain(|d| {d as f64 / 2f64}));
466 }
467
468 #[test]
469 fn macro_chain() {
470 fn some_func(a: i64) -> i64 {
471 a
472 }
473 fn another_func(b: i64) -> i64 {
474 b + 1
475 }
476 assert_eq!(3, chain!(some_func(1), another_func, another_func));
477 }
478
479 #[test]
480 fn macro_chain_closure() {
481 fn some_func(a: i64) -> i64 {
482 a
483 }
484 fn some_add(a: i64, b: i64, c: i64) -> i64 {
485 a + b + c
486 }
487 fn pass_through(v: f64) -> f64 {
488 v
489 }
490 assert_eq!(2, chain!(some_func(1), |a| {return a + 1}, |b| {return b * 1}, some_func, some_func));
491 assert_eq!(6f64, chain!(some_add(1, 2, 3), |result: i64| {(result as f64).powi(2)}, |sqr: f64| {sqr.powf(0.5)}, pass_through, pass_through));
492 }
493
494 #[test]
495 fn macro_chain_moved_closure() {
496 fn some_func(a: i64) -> i64 {
497 a
498 }
499 let value = 2;
500 let one = 1;
501 assert_eq!(3, chain!(some_func(1), move |a| {return a + value}, move |b| {return b * one}, some_func, some_func));
502 assert_eq!(3, chain!(some_func(1), |a| {return a + value}, move |b| {return b * one}, some_func, some_func));
503 assert_eq!(3, chain!(some_func(1), move |a| {return a + value}, |b| {return b * one}, some_func, some_func));
504 }
505}