magriette/
lib.rs

1//! # Examples
2//! ```
3//! # use magriette::pipe;
4//! #
5//! fn dederef(x: &&u32) -> u32 {
6//!    **x
7//! }
8//!
9//! fn lol(xs: &[u32], ys: &[usize]) -> Option<u32> {
10//!    // An even worse way of writing `Some(dederef(&xs.get(*ys.get(123)?)?))`
11//!    pipe!(ys -> .get(123) -> ?*xs.get -> ?&dederef -> Some)
12//! }
13//! ```
14#![no_std]
15
16#[macro_export]
17macro_rules! pipe {
18   (@finish $x:expr, -> $($xs:tt)+) => {
19      $crate::pipe!(@start $x, [], $($xs)+)
20   };
21   (@finish $x:expr, => $($xs:tt)+) => {
22      $crate::pipe!(@start2 $x, [], [], $($xs)+)
23   };
24   (@finish $x:expr,) => {
25      $x
26   };
27   (@call ($($x:expr),+), [$($f:tt)+], ($($y:expr),*$(,)?). $($xs:tt)*) => {
28      $crate::pipe!(@call ($($x),+), [$($f)+($($y),*).], $($xs)*)
29   };
30   (@call ($($x:expr),+), [$($f:tt)+], ($($y:expr),*$(,)?)? $($xs:tt)*) => {
31      $crate::pipe!(@call ($($x),+), [$($f)+($($y),*)?], $($xs)*)
32   };
33   (@call ($($x:expr),+), [$($f:tt)+], ($($y:expr),+$(,)?)($($z:expr),+$(,)?) $($xs:tt)*) => {
34      $crate::pipe!(@call ($($y,)+ $($x),+), [$($f)+], ($($z),+) $($xs)*)
35   };
36   (@call ($($x:expr),+), [$($f:tt)+], ($($y:expr),+$(,)?) $($xs:tt)*) => {
37      $crate::pipe!(@finish $($f)+($($y,)+ $($x),+), $($xs)*)
38   };
39   (@call ($($x:expr),+), [$($f:tt)+], -> $($xs:tt)*) => {
40      $crate::pipe!(@start $($f)+($($x),+), [], $($xs)+)
41   };
42   (@call ($($x:expr),+), [$($f:tt)+], => $($xs:tt)*) => {
43      $crate::pipe!(@start2 $($f)+($($x),+), [], [], $($xs)+)
44   };
45   (@call ($($x:expr),+), [$($f:tt)+],) => {
46      $($f)+($($x),+)
47   };
48   (@call ($($x:expr),+), [$($f:tt)+], $y:tt $($xs:tt)*) => {
49      $crate::pipe!(@call ($($x),+), [$($f)+$y], $($xs)*)
50   };
51   (@method $x:expr, [$($f:tt)+]($($y:expr),*), [$($z:expr),*], ::<$($t:ty),+$(,)?> $($xs:tt)*) => {
52      $crate::pipe!(@method $x, [$($f)+::<$($t),+>]($($y,)*), [$($z),*], $($xs)*)
53   };
54   (
55      @method $x:expr,
56      [$($f:tt)+]($($y:expr),*),
57      [$($z:expr),*],
58      ($($zz:expr),+$(,)?) $($xs:tt)*) =>
59   {
60      $crate::pipe!(@method $x, [$($f)+]($($y,)* $($zz),+), [$($z),*], $($xs)*)
61   };
62   (@method $x:expr, [$($f:tt)+]($($y:expr),*), [$($z:expr),*], $($xs:tt)*) => {
63      $crate::pipe!(@finish ($x).$($f)+($($y,)*$($z),*), $($xs)*)
64   };
65   (@start $x:expr, [$($u:tt)*], &mut $($xs:tt)*) => {
66      $crate::pipe!(@start $x, [$($u)* &mut], $($xs)*)
67   };
68   (@start $x:expr, [$($u:tt)*], && $($xs:tt)*) => {
69      $crate::pipe!(@start $x, [$($u)* &&], $($xs)*)
70   };
71   (@start $x:expr, [$($u:tt)*], & $($xs:tt)*) => {
72      $crate::pipe!(@start $x, [$($u)* &], $($xs)*)
73   };
74   (@start $x:expr, [$($u:tt)*], * $($xs:tt)*) => {
75      $crate::pipe!(@start $x, [$($u)* *], $($xs)*)
76   };
77   (@start $x:expr, [$($u:tt)*], await $($xs:tt)*) => {
78      $crate::pipe!(@start ($x).await, [$($u)*], $($xs)*)
79   };
80   (@start $x:expr, [$($u:tt)*], ? $($xs:tt)*) => {
81      $crate::pipe!(@start ($x)?, [$($u)*], $($xs)*)
82   };
83   (@start $x:expr, [$($u:tt)*], -> $($xs:tt)+) => {
84      $crate::pipe!(@start $($u)*($x), [], $($xs)+)
85   };
86   (@start $x:expr, [$($u:tt)*], => $($xs:tt)+) => {
87      $crate::pipe!(@start2 $($u)*($x), [], [], $($xs)+)
88   };
89   (@start $x:expr, [$($u:tt)*], match $c:tt $($xs:tt)*) => {
90      $crate::pipe!(@finish match $($u)*($x) $c, $($xs)*)
91   };
92   (@start $x:expr, [$($u:tt)*], if $t:block else $f:block $($xs:tt)*) => {
93      $crate::pipe!(@finish if $($u)*($x) $t else $f, $($xs)*)
94   };
95   (@start $x:expr, [$($u:tt)*], $f:ident $($xs:tt)*) => {
96      $crate::pipe!(@call ($($u)*($x)), [$f], $($xs)*)
97   };
98   (@start $x:expr, [$($u:tt)*], .$f:ident $($xs:tt)*) => {
99      $crate::pipe!(@method $($u)*($x), [$f](), [], $($xs)*)
100   };
101   (@start $x:expr, [$($u:tt)*], [.$($p:tt)+] $($xs:tt)*) => {
102      $crate::pipe!(@finish ($($u)*($x)).$($p)+, $($xs)*)
103   };
104   (@start $x:expr, [$($u:tt)*], [$i:expr] $($xs:tt)*) => {
105      $crate::pipe!(@finish ($($u)*($x))[$i], $($xs)*)
106   };
107   (@start $x:expr, [$($u:tt)*], _) => {{
108      let _ = $($u)*($x);
109   }};
110   (@start $x:expr, [$($u:tt)*], |$y:pat_param| $e:block $($xs:tt)*) => {
111      $crate::pipe!(@finish (|$y| $e)($($u)*($x)), $($xs)*)
112   };
113   (@start $x:expr, [$($u:tt)*],) => {
114      $($u)*($x)
115   };
116   (@start2 $x:expr, [$($u:tt)*], [$($s:tt)*], &mut $($xs:tt)*) => {
117      $crate::pipe!(@start2 $x, [$($u)* &mut], [$($s)*], $($xs)*)
118   };
119   (@start2 $x:expr, [$($u:tt)*], [$($s:tt)*], && $($xs:tt)*) => {
120      $crate::pipe!(@start2 $x, [$($u)* &&], [$($s)*], $($xs)*)
121   };
122   (@start2 $x:expr, [$($u:tt)*], [$($s:tt)*], & $($xs:tt)*) => {
123      $crate::pipe!(@start2 $x, [$($u)* &], [$($s)*], $($xs)*)
124   };
125   (@start2 $x:expr, [$($u:tt)*], [$($s:tt)*], * $($xs:tt)*) => {
126      $crate::pipe!(@start2 $x, [$($u)* *], [$($s)*], $($xs)*)
127   };
128   (@start2 $x:expr, [$($u:tt)*], [$($s:tt)*], await $($xs:tt)*) => {
129      $crate::pipe!(@start2 $x, [$($u)*], [$($s)*.await], $($xs)*)
130   };
131   (@start2 $x:expr, [$($u:tt)*], [$($s:tt)*], ? $($xs:tt)*) => {
132      $crate::pipe!(@start2 $x, [$($u)*], [$($s)*?], $($xs)*)
133   };
134   (@start2 $x:expr, [$($u:tt)*], [$($s:tt)*], -> $($xs:tt)+) => {{
135      #[allow(unused_mut)]
136      let mut x = $x;
137      $crate::pipe!(@start ($($u)*x.0$($s)*, $($u)*x.1$($s)*), [], $($xs)+)
138   }};
139   (@start2 $x:expr, [$($u:tt)*], [$($s:tt)*], => $($xs:tt)+) => {{
140      #[allow(unused_mut)]
141      let mut x = $x;
142      $crate::pipe!(@start2 ($($u)*x.0$($s)*, $($u)*x.1$($s)*), [], [], $($xs)+)
143   }};
144   (@start2 $x:expr, [$($u:tt)*], [$($s:tt)*], match $c:tt $($xs:tt)*) => {{
145      #[allow(unused_mut)]
146      let mut x = $x;
147      $crate::pipe!(@finish match ($($u)*x.0$($s)*, $($u)*x.1$($s)*) $c, $($xs)*)
148   }};
149   (@start2 $x:expr, [$($u:tt)*], [$($s:tt)*], $f:ident $($xs:tt)*) => {{
150      #[allow(unused_mut)]
151      let mut x = $x;
152      $crate::pipe!(@call ($($u)*x.0$($s)*, $($u)*x.1$($s)*), [$f], $($xs)*)
153   }};
154   (
155      @start2 $x:expr,
156      [$($u:tt)*],
157      [$($s:tt)*],
158      |$y:pat_param, $z:pat_param| $e:block $($xs:tt)*) =>
159   {{
160      #[allow(unused_mut)]
161      let mut x = $x;
162      $crate::pipe!(@finish (|$y, $z| $e)($($u)*x.0$($s)*, $($u)*x.1$($s)*), $($xs)*)
163   }};
164   (@start2 $x:expr, [$($u:tt)*], [$($s:tt)*],) => {{
165      #[allow(unused_mut)]
166      let mut x = $x;
167      ($($u)*x.0$($s)*, $($u)*x.1$($s)*)
168   }};
169   (@init [$($x:tt)+], -> $($xs:tt)+) => {
170      $crate::pipe!(@start $($x)+, [], $($xs)+)
171   };
172   (@init [$($x:tt)+], => $($xs:tt)+) => {
173      $crate::pipe!(@start2 $($x)+, [], [], $($xs)+)
174   };
175   (@init [$($x:tt)+], $x1:tt $($xs:tt)*) => {
176      $crate::pipe!(@init [$($x)+$x1], $($xs)*)
177   };
178   (@init [$x:expr],) => {
179      $x
180   };
181   (@$($xs:tt)*) => {
182      compile_error!("Failed to match rule")
183   };
184   ($x:tt $($xs:tt)*) => {
185      $crate::pipe!(@init [$x], $($xs)*)
186   };
187}
188
189#[cfg(test)]
190mod tests {
191   mod foo {
192      pub fn ident<T>(x: T) -> T {
193         x
194      }
195
196      pub fn second<T>(_: T, x: T) -> T {
197         x
198      }
199
200      pub fn third<T>(_: T, _: T, x: T) -> T {
201         x
202      }
203   }
204
205   mod bar {
206      pub fn wrap<T>(x: T) -> Option<T> {
207         Some(x)
208      }
209
210      pub fn wrap2<T>(x: T, y: T) -> (Option<T>, Option<T>) {
211         (Some(x), Some(y))
212      }
213   }
214
215   use bar::*;
216   use foo::*;
217
218   #[test]
219   fn r#ref() {
220      assert_eq!(&0, pipe!(0 -> & -> ident));
221      assert_eq!(&0, pipe!(0 -> &ident));
222      assert_eq!(&mut 0, pipe!(0 -> &mut -> foo::ident));
223      assert_eq!(&mut 0, pipe!(0 -> &mut foo::ident::<&mut u32>));
224      assert_eq!(0, pipe!(0 -> & -> second(&1) -> *));
225      assert_eq!(0, pipe!(0 -> &&second(&&1) -> **));
226      assert_eq!(0, pipe!(0 -> &mut -> foo::third(&mut 1, &mut 2) -> *));
227      assert_eq!(0, pipe!(0 -> &mut foo::third(&mut 1)(&mut 2) -> *));
228
229      assert_eq!(1, pipe!((0, 1) => & => second -> *));
230      assert_eq!(1, pipe!((0, 1) => &second -> *));
231      assert_eq!(1, pipe!((0, 1) => &mut  => second -> *));
232      assert_eq!(1, pipe!((0, 1) => &mut second -> *));
233      assert_eq!(1, pipe!((0, 1) => && => second -> **));
234      assert_eq!(1, pipe!((0, 1) => &&second -> **));
235      assert_eq!(1, pipe!((0, 1) => &third(&2) -> *));
236   }
237
238   #[test]
239   fn r#try() {
240      fn inner() -> Option<()> {
241         assert_eq!(0, pipe!(Some(0) -> ? -> ident));
242         assert_eq!(0, pipe!(Some(0) -> ?foo::ident));
243         assert_eq!(0, pipe!(0 -> wrap -> ?));
244         assert_eq!(0, pipe!(Some(0) -> bar::wrap -> ? -> ?));
245         assert_eq!(0, pipe!(Some(0) -> bar::wrap -> ??));
246         assert_eq!((0, 1), pipe!((0, 1) => wrap2 => ?));
247         assert_eq!((0, 1), pipe!((0, 1) => bar::wrap2 => ?));
248         assert_eq!((0, 1), pipe!((Some(0), Some(1)) => ?wrap2 => ?));
249         assert_eq!((0, 1), pipe!((Some(0), Some(1)) => ?bar::wrap2 => ?));
250         pipe!(None::<()> -> bar::wrap -> ??);
251         unreachable!();
252      }
253      inner();
254   }
255
256   #[test]
257   fn method() {
258      #[derive(Debug, PartialEq, Eq)]
259      struct U32(u32);
260
261      impl U32 {
262         fn incr(self) -> U32 {
263            U32(self.0 + 1)
264         }
265
266         fn add2(&self, b: u32) -> U32 {
267            U32(self.0 + b)
268         }
269
270         fn add3(&mut self, b: u32, c: u32) -> U32 {
271            U32(self.0 + b + c)
272         }
273
274         fn add4(&mut self, b: u32, c: u32, d: u32) -> U32 {
275            U32(self.0 + b + c + d)
276         }
277
278         fn add_assign(&mut self, b: u32) -> U32 {
279            self.0 += b;
280            U32(self.0)
281         }
282
283         fn konst<T>(&self, x: T) -> T {
284            x
285         }
286      }
287
288      let mut x = U32(0);
289      assert_eq!(U32(1), pipe!(U32(0) -> .incr));
290      assert_eq!(U32(1), pipe!(U32(0) -> .add2(1)));
291      assert_eq!(U32(2), pipe!(U32(0) -> &.add2(1) -> .incr));
292      assert_eq!(U32(3), pipe!(U32(0) -> .add3(1, 2)));
293      assert_eq!(U32(4), pipe!(U32(0) -> &mut .add3(1, 2) -> .incr));
294      assert_eq!(U32(5), pipe!(5 -> x.add_assign));
295      assert_eq!(U32(6), pipe!(0 -> x.add3(1)));
296      assert_eq!(U32(7), pipe!(U32(0) -> .konst::<_>(U32(7))));
297      assert_eq!(U32(8), pipe!((1, 2) => x.add3));
298      assert_eq!(U32(9), pipe!((0, 1) => x.add4(3)));
299   }
300
301   #[test]
302   fn index() {
303      let xs = [0, 1, 2];
304      assert_eq!(0, pipe!(xs -> [0]));
305      assert_eq!(1, pipe!(&xs -> [1]));
306      assert_eq!(2, pipe!(xs -> &[1 + 1]));
307      assert_eq!(3, pipe!(xs -> &[2] -> |x| { x + 1 }));
308   }
309
310   #[test]
311   fn access() {
312      struct Foo(u32, u32);
313
314      struct Bar {
315         a: u32,
316         b: Foo,
317      }
318
319      let x = (0, 1);
320      let y = Foo(2, 3);
321      let z = Bar { a: 4, b: Foo(5, 6) };
322      assert_eq!(0, pipe!(x -> [.0]));
323      assert_eq!(1, pipe!(x -> &[.1]));
324      assert_eq!(2, pipe!(&y -> [.0]));
325      assert_eq!(3, pipe!(&y -> [.1]));
326      assert_eq!(4, pipe!(&z -> [.a]));
327      assert_eq!(5, pipe!(z -> &[.b] -> [.0]));
328      assert_eq!(6, pipe!(&z -> &[.b.1]));
329   }
330
331   #[test]
332   fn sink() {
333      assert_eq!((), pipe!(0 -> _));
334   }
335
336   #[test]
337   fn r#match() {
338      assert_eq!(0, pipe!(false -> match { false => 0, true => 1}));
339      assert_eq!(
340         1,
341         pipe!(false
342            -> match { false => true, true => false}
343            -> *&match { false => 0, true => 1}),
344      );
345      assert_eq!((1, 2), pipe!((0, 1) => &match { (x, y) => (*x + 1, *y + 1) }));
346   }
347
348   #[test]
349   fn r#if() {
350      assert_eq!(0, pipe!(false -> if { 1 } else { 0 }));
351      assert_eq!(
352         1,
353         pipe!(false
354            -> if { false } else { true }
355            -> *&if { 1 } else { 0 }),
356      );
357   }
358
359   #[test]
360   fn closure() {
361      assert_eq!(1, pipe!(0 -> |x| { x + 1 }));
362      assert_eq!(
363         2,
364         pipe!(0 -> |x| {
365             let x = x + 1;
366             x + 1
367         }),
368      );
369      assert_eq!(
370         3,
371         pipe!(0
372            -> |x| {
373                let x = x + 1;
374                x + 1
375            }
376            -> |x| { x + 1 }),
377      );
378      assert_eq!(4, pipe!((0, 1) -> |(x, y)| { (x + 1, y + 1) } => |x, y| { x + y + 1 }));
379   }
380
381   #[test]
382   fn combo() {
383      struct Foo(Option<u32>);
384
385      impl Foo {
386         fn new(x: Option<u32>) -> Self {
387            Self(x)
388         }
389
390         fn wrap(&self) -> Option<Option<u32>> {
391            Some(self.0)
392         }
393
394         fn wrap_add(&self, x: u32) -> Option<Option<u32>> {
395            Some(self.0.map(|y| y + x))
396         }
397      }
398
399      fn inner() -> Option<()> {
400         assert_eq!(0, pipe!(Some(0) -> *&?bar::wrap -> ?));
401         assert_eq!(0, pipe!(Some(Some(Foo(Some(0)))) -> ?&&&*&&&*&?.wrap -> ??));
402         assert_eq!(1, pipe!(Some(0) -> ?Foo::new(Some(1)).wrap_add -> ??));
403         Some(())
404      }
405      inner();
406   }
407
408   #[test]
409   fn pointless() {
410      assert_eq!(0, pipe!(0 -> pipe! -> pipe!));
411   }
412}