fn_chain/
lib.rs

1//! Utilities macro/function to ease function chain to be less verbose.
2//! 
3//! This crate provide two usage style, a macro `chain` and a function `chain`.
4//! 
5//! # Sample showcase
6//! ## Case 1 chain by using a helper macro
7//! ```rust
8//! use fn_chain::chain;
9//! 
10//! fn simple_add(a : i32, b : i32, c : i32) -> i32 {
11//!     a + b + c
12//! }
13//! 
14//! fn pass_through(v : f64) -> f64 {
15//!     v
16//! }
17//! 
18//! assert_eq!(
19//!     6f64, 
20//!     chain!(
21//!         simple_add(1, 2, 3), 
22//!         |result: i32| {(result as f64).powi(2)}, 
23//!         |sqr: f64| {sqr.powf(0.5)},
24//!         pass_through,
25//!         pass_through
26//!     )
27//! );
28//! // This macro will expand to:
29//! assert_eq!(
30//!     6f64, 
31//!     pass_through(
32//!         pass_through(
33//!             (|sqr: f64| {sqr.powf(0.5)})(
34//!                 (|result: i32| {(result as f64).powi(2)})(
35//!                     simple_add(1, 2, 3)
36//!                 )
37//!             )
38//!         )
39//!     )
40//! );
41//! ```
42//! ## Case 2 chain by using helper function
43//! ```rust
44//! use fn_chain::chain;
45//! 
46//! fn simple_add(a : i32, b : i32, c : i32) -> i32 {
47//!     a + b + c
48//! }
49//! 
50//! fn pass_through(v : f64) -> f64 {
51//!     v
52//! }
53//! 
54//! assert_eq!(6f64, *chain(simple_add(1, 2, 3))
55//!                         .chain(|result| {(result as f64).powi(2)})
56//!                         .chain(|sqr| sqr.powf(0.5))
57//!                         .chain(pass_through)
58//!                         .chain(pass_through));
59//! ```
60
61/// A macro counterpart of function [chain](fn.chain.html) which reduce verbosity
62/// and defer the execution until entire chain is formed.
63/// 
64/// This macro will expanded to a nested function call, not a (Chainable)[struct.Chainable.html] struct.
65/// 
66/// For example: 
67/// ```rust
68/// use fn_chain::chain;
69/// let result = chain!((|a, b, c| a + b + c)(1i32, 2, 3), |d| d * 2);
70/// assert_eq!(12, result);
71/// // The macro will expand into something like this
72/// assert_eq!(
73///     12,
74///     (|d| d * 2)((|a, b, c| a + b + c)(1i32, 2, 3))
75/// );
76/// ```
77/// Another example using function:
78/// ```rust
79/// use fn_chain::chain;
80/// fn function(a : i32, b : i32, c : i32) -> i32{
81///     a + b + c
82/// }
83/// fn subsequence_function(d: i32) -> i32 {
84///     d * 2
85/// }
86/// let outer = 2;
87/// let result = chain!(
88///                 function(1, 2, 3), 
89///                 |e| e + 1, 
90///                 move |f| f * outer, 
91///                 subsequence_function, 
92///                 subsequence_function);
93/// assert_eq!(56, result);
94/// // This macro will be expanded to:
95/// assert_eq!(56, 
96///     subsequence_function(
97///         subsequence_function(
98///             (move |f| f * outer)(
99///                 (|e| e + 1)(
100///                     function(1, 2, 3)
101///                 )
102///             )
103///         )
104///     )
105/// )
106/// ```
107#[macro_export]
108macro_rules! chain {
109    // call chain with single function
110    ($function: ident($($params: expr),*)) => {
111        $function($($params),*)
112    };
113    // call chain with single closure block stmt with immediate execution
114    (|$($c_params: ident),*| $body: block($($expr: expr),*)) => {
115        (|$($c_params),*| $body)($($expr),*)
116    };
117    // call chain with single any kind of expression closure wrap inside parenthesis with immediate execution
118    ((|$($c_params: ident),*| $body: expr)($($expr: expr),*)) => {
119        (|$($c_params),*| $body)($($expr),*)
120    };
121    // call chain with single moved closure block stmt with immediate execution
122    (move |$($c_params: ident),*| $body: block($($expr: expr),*)) => {
123        (move |$($c_params),*| $body)($($expr),*)
124    };
125    // call chain with single any kind of expression moved closure wrap inside parenthesis with immediate execution
126    ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*)) => {
127        (move |$($c_params),*| $body)($($expr),*)
128    };
129    // call chain with single borrow closure block stmt with immediate execution
130    (&|$($c_params: ident),*| $body: block($(*$expr: expr),*)) => {
131        (&|$($c_params),*| $body)($($expr),*)
132    };
133    // call chain with single any kind of expression borrow closure wrap inside parenthesis with immediate execution
134    ((&|$($c_params: ident),*| $body: expr)($($expr: expr),*)) => {
135        (&|$($c_params),*| $body)($($expr),*)
136    };
137    // call chain with single borrow muit closure block stmt with immediate execution
138    (& mut |$($c_params: ident),*| $body: block($($expr: expr),*)) => {
139        (& mut |$($c_params),*| $body)($($expr),*)
140    };
141    // call chain with single any kind of expression borrow mut closure wrap inside parenthesis with immediate execution
142    ((& mut |$($c_params: ident),*| $body: expr)($($expr: expr),*)) => {
143        (|$($c_params),*| $body)($($expr),*)
144    };
145    // chain of two functions
146    ($function: ident($($params: expr),*), $function2: ident) => {
147        $function2($function($($params),*))
148    };
149    // chain of a function before closure
150    ($function: ident($($params: expr),*), |$c_params: ident| $body: expr) => {
151        (|$c_params| $body)($function($($params),*))
152    };
153    // chain of a function before closure specifying type of params in a closure
154    ($function: ident($($params: expr),*), |$c_params: ident: $ty: ident| $body: expr) => {
155        (|$c_params: $ty| $body)($function($($params),*))
156    };
157    // chain of a function before closure specifying borrow type of params in a closure
158    ($function: ident($($params: expr),*), |$c_params: ident: & $ty: ident| $body: expr) => {
159        (|$c_params: $ty| $body)($function($($params),*))
160    };
161    // chain of a function before closure specifying borrow mut type of params in a closure
162    ($function: ident($($params: expr),*), |$c_params: ident: & mut $ty: ident| $body: tt) => {
163        (|$c_params: $ty| $body)($function($($params),*))
164    };
165    // chain of a function before moved closure
166    ($function: ident($($params: expr),*), move |$c_params: ident| $body: tt) => {
167        (move |$c_params| $body)($function($($params),*))
168    };
169    // chain of a function before moved closure specifying type of params in a closure
170    ($function: ident($($params: expr),*), move |$c_params: ident: $ty: ident| $body: tt) => {
171        (move |$c_params: $ty| $body)($function($($params),*))
172    };
173    // chain of a function before moved closure specifying borrow type of params in a closure
174    ($function: ident($($params: expr),*), move |$c_params: ident: & $ty: ident| $body: tt) => {
175        (move |$c_params: $ty| $body)($function($($params),*))
176    };
177    // chain of a function before moved closure specifying borrow mut type of params in a closure
178    ($function: ident($($params: expr),*), move |$c_params: ident: & mut $ty: ident| $body: tt) => {
179        (move |$c_params: $ty| $body)($function($($params),*))
180    };
181    // chain of multiple functions
182    ($function: ident($($params: expr),*), $function2: ident, $($more_func: ident),+) => {
183        chain!($function2($function($($params),*)), $($more_func),*)
184    };
185    // call chain of closure execution follow by function
186    ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), $func: ident) => {
187        $func((|$($c_params),*| $body)($($expr),*))
188    };
189    // call chain of moved closure execution follow by function
190    ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), $func: ident) => {
191        $func((move |$($c_params),*| $body)($($expr),*))
192    };
193    // call chain of closure execution follow by another closure
194    ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), |$($c2_params: ident),*| $body2: expr) => {
195        (|$($c2_params),*| $body2)((|$($c_params),*| $body)($($expr),*))
196    };
197    // call chain of moved closure execution follow by another closure
198    ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), |$c2_params: ident| $body2: expr) => {
199        (|$c2_params| $body2)((move |$($c_params),*| $body)($($expr),*))
200    };
201    // call chain of closure execution with typed parameter follow by function
202    ((|$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), $func: ident) => {
203        $func((|$($c_params: $ty),*| $body)($($expr),*))
204    };
205    // call chain of moved closure execution with typed parameter follow by function
206    ((move |$($c_params: ident: $ty: ty),*| $body: expr)($expr: expr), $func: ident) => {
207        $func((move |$($c_params: $ty),*| $body)($($expr),*))
208    };
209    // call chain of closure execution follow by closure
210    ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), |$c2_params: ident| $body2: expr) => {
211        (|$c2_params| $body2)((|$($c_params),*| $body)($($expr),*))
212    };
213    // call chain of closure execution follow by moved closure
214    ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), move |$c2_params: ident| $body2: expr) => {
215        (move |$c2_params| $body2)((|$($c_params),*| $body)($($expr),*))
216    };
217    // call chain of moved closure execution follow by another moved closure
218    ((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    // call chain of closure execution with typed parameter follow by another closure
222    ((|$($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    // call chain of moved closure execution with typed parameter follow by another closure
226    ((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    // call chain of closure execution with typed parameter follow by moved closure
230    ((|$($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    // call chain of moved closure execution with typed parameter follow by another moved closure
234    ((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    // call chain of closure execution follow by another closure
238    ((|$($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    // call chain of moved closure execution follow by another closure
242    ((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    // call chain of closure execution follow by moved closure
246    ((|$($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    // call chain of moved closure execution follow by another moved closure
250    ((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    // call chain of closure with typed parameter follow by another closure with typed parameter
254    ((|$($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    // call chain of moved closure with typed parameter follow by another closure with typed parameter
258    ((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    // call chain of closure with typed parameter follow by move closure with typed parameter
262    ((|$($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    // call chain of moved closure with typed parameter follow by another moved closure with typed parameter
266    ((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    // multiple chain begin by function then closure then anything else
270    ($function: ident($($params: expr),*), |$c_params: ident| $body: expr, $($other: tt)*) => {
271        chain!((|$c_params| $body)($function($($params),*)), $($other)*)
272    };
273    // multiple chain begin by function then move closure then anything else
274    ($function: ident($($params: expr),*), move |$c_params: ident| $body: expr, $($other: tt)*) => {
275        chain!((move |$c_params| $body)($function($($params),*)), $($other)*)
276    };
277    // multiple chain begin by closure then function then anything else
278    ((|$($c_params: ident),*| $body: expr)($($expr: expr),*), $function: ident, $($other: tt)*) => {
279        chain!($function((|$c_params| $body)($($expr),*)), $($other)*)
280    };
281    // multiple chain begin by moved closure then function then anything else
282    ((move |$($c_params: ident),*| $body: expr)($($expr: expr),*), $function: ident, $($other: tt)*) => {
283        chain!($function((move |$($c_params),*| $body)($($expr),*)), $($other)*)
284    };
285    // multiple chain begin by closure then closure then anything else
286    ((|$($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    // multiple chain begin by moved closure then closure then anything else
290    ((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    // multiple chain begin by closure then move closure then anything else
294    ((|$($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    // multiple chain begin by move closure then move closure then anything else
298    ((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    // multiple chain begin by function then closure with typed params then anything else
302    ($function: ident($($params: expr),*), |$c_params: ident: $ty: ty| $body: expr, $($other: tt)*) => {
303        chain!((|$c_params: $ty| $body)($function($($params),*)), $($other)*)
304    };
305    // multiple chain begin by function then moved closure with typed params then anything else
306    ($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    // multiple chain begin by closure with typed param then function then anything else
310    ((|$($c_params: ident: $ty: ty),*| $body: expr)($($expr: expr),*), $function: ident, $($other: tt)*) => {
311        chain!($function((|$($c_params: $ty),*| $body)($($expr),*)), $($other)*)
312    };
313    // multiple chain begin by moved closure with typed param then function then anything else
314    ((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    // multiple chain begin by closure then closure then anything else
318    ((|$($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    // multiple chain begin by closure then closure then anything else
322    ((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    // multiple chain begin by closure with typed params then closure then anything else
326    ((|$($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    // multiple chain begin by moved closure with typed params then closure then anything else
330    ((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    // multiple chain begin by closure with typed params then moved closure then anything else
334    ((|$($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    // multiple chain begin by moved closure with typed params then moved closure then anything else
338    ((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    // multiple chain begin by closure then closure with typed params then anything else
342    ((|$($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    // multiple chain begin by moved closure then closure with typed params then anything else
346    ((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    // multiple chain begin by closure then moved closure with typed params then anything else
350    ((|$($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    // multiple chain begin by moved closure then moved closure with typed params then anything else
354    ((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    // multiple chain begin by closure then closure, both are typed params, then anything else
358    ((|$($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    // multiple chain begin by moved closure then closure, both are typed params, then anything else
362    ((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    // multiple chain begin by closure then moved closure, both are typed params, then anything else
366    ((|$($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    // multiple chain begin by moved closure then moved closure, both are typed params, then anything else
370    ((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
375/// Chainable struct that permit user to rapidly call [chain method](struct.Chainable.html#method.chain)
376/// to chain multiple function together using previous function returned value as input
377/// to the next function in chain.
378/// 
379/// It is usually construct by using function [chain](fn.chain.html).
380pub struct Chainable<R> {
381    val: R
382}
383
384impl<R> Chainable<R> {
385    /// Consume current chain and produce a new [Chainable](struct.Chainable.html) 
386    /// that can further [chain](struct.Chainable.html#method.chain) as needed.
387    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    /// Consume the chain and release it result
394    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
407/// A function that take an expression which return a single value or object then
408/// return a [Chainable](struct.Chainable.html) then it can be chain with other function/closure
409/// with method [chain](struct.Chainable.html#method.chain) of [Chainable.](struct.Chainable.html)
410/// 
411/// ## Example
412/// ```rust
413/// use fn_chain::chain;
414/// 
415/// fn function1(a : i32, b : i32, c : i32) -> i32 {
416///     a + b + c
417/// }
418/// 
419/// fn function2(d : i32) -> i32 {
420///     d + 1
421/// }
422/// 
423/// let var = 2;
424/// let chained = chain(function1(1, 2, 3))
425///                     .chain(function2)
426///                     .chain(|param| param + 2)
427///                         .chain(move |param| param * var);
428/// assert_eq!(18, *chained);
429/// // Chainable struct implement Deref to obtain final result.
430/// // There's also `end` method that consume Chainable and return result.
431/// assert_eq!(18, chained.end());
432/// // chained no longer exist as it was consumed by end()
433/// ```
434pub 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}