pipeline/
lib.rs

1//! # pipe_macros
2//! A small macro library that allows you to pipe functions
3//! similar to the pipe operator in Elixir and F# (|>)
4
5#![deny(missing_docs)]
6#![deny(warnings)]
7
8#[macro_export]
9macro_rules! pipe_fun {
10    (&, $ret:expr) => {
11        &$ret;
12    };
13    ((as $typ:ty), $ret:expr) => {
14        $ret as $typ;
15    };
16    ({$fun:expr}, $ret:expr) => {
17        $fun($ret);
18    };
19    ([$fun:ident], $ret:expr) => {
20        $ret.$fun();
21    };
22    (($fun:ident($($arg:expr),*)), $ret:expr) => {
23        $fun($ret $(,$arg)*);
24    };
25    ($fun:ident, $ret:expr) => {
26        $fun($ret);
27    }
28}
29
30#[macro_export]
31macro_rules! pipe {
32    ( $expr:expr => $($funs:tt)=>+ ) => {
33        {
34            let ret = $expr;
35            $(
36                let ret = pipe_fun!($funs, ret);
37            )*
38            ret
39        }
40    };
41}
42
43#[macro_export]
44macro_rules! pipe_res {
45    ( $expr:expr => $($funs:tt)=>+ ) => {
46        {
47            let ret = Ok($expr);
48            $(
49                let ret = match ret {
50                    Ok(x) => pipe_fun!($funs, x),
51                    _ => ret
52                };
53            )*
54            ret
55        }
56    };
57}
58
59#[macro_export]
60macro_rules! pipe_opt {
61    ( $expr:expr => $($funs:tt)=>+ ) => {
62        {
63            let ret = None;
64            $(
65                let ret = match ret {
66                    None => pipe_fun!($funs, $expr),
67                    _ => ret
68                };
69            )*
70            ret
71        }
72    };
73}
74
75#[cfg(test)]
76mod test_pipe_opt{
77    fn times2(a: u32) -> Option<u32>{
78        return Some(a * 2);
79    }
80
81    fn nope(_a: u32) -> Option<u32>{
82        return None;
83    }
84
85    #[test]
86    fn accepts_options() {
87        let ret = pipe_opt!(
88            4
89            => times2
90        );
91
92        assert_eq!(ret, Some(8));
93    }
94
95    #[test]
96    fn accepts_unwrap() {
97        let ret = pipe_opt!(
98            4
99            => times2
100        ).unwrap();
101
102        assert_eq!(ret, 8);
103    }
104
105
106    #[test]
107    fn exits_early() {
108        let ret = pipe_opt!(
109            4
110            => times2
111            => times2
112            => times2
113        );
114
115        assert_eq!(ret, Some(8));
116    }
117
118    #[test]
119    fn goes_until_some() {
120        let ret = pipe_opt!(
121            4
122            => nope
123            => nope
124            => {|_i: u32| None}
125            => times2
126            => nope
127        );
128
129        assert_eq!(ret, Some(8));
130    }
131
132    #[test]
133    fn ends_with_none() {
134        let ret = pipe_opt!(
135            4
136            => nope
137            => nope
138            => {|_i: u32| None}
139            => nope
140        );
141
142        assert_eq!(ret, None);
143    }
144}
145
146
147#[cfg(test)]
148mod test_pipe_res{
149    fn times2(a: u32) -> Result<u32, String>{
150        return Ok(a * 2);
151    }
152
153    fn fail_if_over_4(a: u32) -> Result<u32, String>{
154        if a > 4 {
155            return Err("This number is larger than four".to_string());
156        }
157        return Ok(a);
158    }
159
160    #[test]
161    fn accepts_results() {
162        let ret = pipe_res!(
163            4
164            => times2
165        );
166
167        assert_eq!(ret, Ok(8));
168    }
169
170    #[test]
171    fn accepts_unwrap() {
172        let ret = pipe_res!(
173            4
174            => times2
175        ).unwrap();
176
177        assert_eq!(ret, 8);
178    }
179
180
181    #[test]
182    fn chains_result_values() {
183        let ret = pipe_res!(
184            4
185            => times2
186            => times2
187            => times2
188        );
189
190        assert_eq!(ret, Ok(32));
191    }
192
193    #[test]
194    fn exits_early() {
195        let ret = pipe_res!(
196            4
197            => times2
198            => fail_if_over_4
199            => times2
200            => times2
201        );
202
203        assert_eq!(ret, Err("This number is larger than four".to_string()));
204    }
205}
206
207#[cfg(test)]
208mod test_pipe{
209    fn times2(a: u32) -> u32{
210        return a * 2;
211    }
212
213    fn times(a: u32, b: u32, c: u32) -> u32{
214        return a * b * c;
215    }
216
217    #[test]
218    fn test_int() {
219        let multiply = |i: u32| i * 2;
220        let ret = pipe!(
221            4
222            => times2
223            => {|i: u32| i * 2}
224            => multiply
225            => (times(100, 10))
226        );
227
228        assert_eq!(ret, 32000);
229    }
230
231    #[test]
232    fn test_string() {
233        let ret = pipe!(
234            "abcd"
235            => [len]
236            => (as u32)
237            => times2
238            => (times(100, 10))
239            => [to_string]
240        );
241
242        //let ret = "abcd";
243        //let ret = ret.len();
244        //let ret = ret as u32;
245        //let ret = times2(ret);
246        //let ret = times(ret, 100, 10);
247        //let ret = ret.to_string();
248
249        assert_eq!(ret, times(times2(("abcd".len() as u32)), 100, 10).to_string());
250        assert_eq!(ret, "8000");
251    }
252}
253