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);
    }
}