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}