1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
#[macro_export] macro_rules! pipe { ($e:expr) => {$e}; ($e:expr => $f:tt) => { $f($e) }; ($e:expr => $f:tt?) => { $f($e)? }; ($e:expr => $f:tt.await) => { $f($e).await }; ($e:expr => $f:tt.await?) => { $f($e).await? }; ($e:expr => $f:tt => $($g:tt)+) => { pipe! { $f($e) => $($g)+ } }; ($e:expr => $f:tt? => $($g:tt)+) => { pipe! { $f($e)? => $($g)+ } }; ($e:expr => $f:tt.await => $($g:tt)+) => { pipe! { $f($e).await => $($g)+ } }; ($e:expr => $f:tt.await? => $($g:tt)+) => { pipe! { $f($e).await? => $($g)+ } }; ($e:expr => $s:tt.$f:tt) => { $s.$f($e) }; ($e:expr => $s:tt.$f:tt?) => { $s.$f($e)? }; ($e:expr => $s:tt.$f:tt.await) => { $s.$f($e).await }; ($e:expr => $s:tt.$f:tt.await?) => { $s.$f($e).await? }; ($e:expr => $s:tt.$f:tt => $($g:tt)+) => { pipe! { $s.$f($e) => $($g)+ } }; ($e:expr => $s:tt.$f:tt? => $($g:tt)+) => { pipe! { $s.$f($e)? => $($g)+ } }; ($e:expr => $s:tt.$f:tt.await => $($g:tt)+) => { pipe! { $s.$f($e).await => $($g)+ } }; ($e:expr => $s:tt.$f:tt.await? => $($g:tt)+) => { pipe! { $s.$f($e).await? => $($g)+ } }; } #[cfg(test)] mod tests { #[test] fn can_compose_simple_functions() { fn double(n: usize) -> usize { n * 2 } fn add(a: usize, b: usize) -> usize { a + b } let actual = pipe!( 2 => double => { |n| add(n, 3) } ); let expected = 7; assert_eq!(expected, actual); } #[test] fn can_compose_functions_returning_results() -> Result<(), Box<dyn std::error::Error>> { fn double(n: usize) -> Result<usize, &'static str> { Ok(n * 2) } fn add(a: usize, b: usize) -> usize { a + b } let actual = pipe!( 2 => double? => { |n| add(n, 3) } => double? => { |n| add(n, 1) } => { |n| add(n, 2) } ); let expected = 17; assert_eq!(expected, actual); Ok(()) } #[test] fn can_compose_async_functions() -> Result<(), Box<dyn std::error::Error>> { smol::block_on(async { async fn double(n: usize) -> Result<usize, &'static str> { Ok(n * 2) } async fn add(a: usize, b: usize) -> Result<usize, &'static str> { Ok(a + b) } let actual = pipe!( 2 => double.await? => { |n| add(n, 3) }.await? => double.await? ); let expected = 14; assert_eq!(expected, actual); Ok(()) }) } #[test] fn can_compose_methods() { struct Utils; impl Utils { fn double(&self, n: usize) -> usize { n * 2 } fn multiply(&self, a: usize, b: usize) -> usize { a * b } } fn add(a: usize, b: usize) -> usize { a + b } let utils = Utils; let actual = pipe!( 8 => utils.double => { |n| add(n, 3) } => { |n| utils.multiply(n, 5) } ); let expected = 95; assert_eq!(expected, actual); } }