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
119
120
121
122
123
124
125
126
127
128
129
130
/// Executes a child process without capturing any output.
///
/// ```
/// # let temp_dir = tempfile::TempDir::new().unwrap();
/// # std::env::set_current_dir(&temp_dir).unwrap();
/// use cradle::prelude::*;
///
/// run!(%"touch ./foo");
/// ```
///
/// If an error occurs, `run!` will panic.
/// See [`crate::error::Error`] for possible errors.
///
/// For capturing output from child processes, see [`crate::run_output!`].
#[macro_export]
macro_rules! run {
    ($($args:tt)*) => {{
        $crate::input::Input::run($crate::tuple_up!($($args)*))
    }}
}

/// Execute child processes, and capture some output.
/// For example you can capture what the child process writes to stdout:
///
/// ```
/// use cradle::prelude::*;
///
/// let StdoutUntrimmed(output) = run_output!(%"echo foo");
/// assert_eq!(output, "foo\n");
/// ```
///
/// [`run_output!`] uses return-type polymorphism.
/// So by using a different return type,
/// you can control what outputs of child processes you want to capture.
/// Here's an example to capture an exit code:
///
/// ```
/// use cradle::prelude::*;
///
/// let Status(status) = run_output!("false");
/// assert_eq!(status.code(), Some(1));
/// ```
///
/// You can use any type that implements [`crate::output::Output`] as the return type.
/// See the module documentation for more comprehensive documentation.
#[macro_export]
macro_rules! run_output {
    ($($args:tt)*) => {{
        $crate::input::Input::run_output($crate::tuple_up!($($args)*))
    }}
}

/// Like [`run_output!`], but fixes the return type to [`Result<T, Error>`],
/// where `T` is any type that implements [`Output`](crate::Output).
#[macro_export]
macro_rules! run_result {
    ($($args:tt)*) => {{
        $crate::input::Input::run_result($crate::tuple_up!($($args)*))
    }}
}

#[doc(hidden)]
#[macro_export]
macro_rules! tuple_up {
    (% $last:expr $(,)?) => {
        $crate::input::Split($last)
    };
    ($last:expr $(,)?) => {
        $last
    };
    (% $head:expr, $($tail:tt)*) => {
        ($crate::input::Split($head), $crate::tuple_up!($($tail)*))
    };
    ($head:expr, $($tail:tt)*) => {
        ($head, $crate::tuple_up!($($tail)*))
    };
}

#[cfg(test)]
mod tests {
    use crate::prelude::*;

    mod tuple_up {
        use super::*;

        #[test]
        #[allow(clippy::eq_op)]
        fn one_value() {
            assert_eq!(tuple_up!(1), 1);
        }

        #[test]
        fn two_values() {
            assert_eq!(tuple_up!(1, 2), (1, 2));
        }

        #[test]
        fn three_values() {
            assert_eq!(tuple_up!(1, 2, 3), (1, (2, 3)));
        }

        #[test]
        fn nested_tuples() {
            assert_eq!(tuple_up!(1, (2, 3), 4), (1, ((2, 3), 4)));
        }

        #[test]
        fn percent_shortcut() {
            assert_eq!(tuple_up!(%"foo"), Split("foo"));
        }

        #[test]
        fn percent_shortcut_with_subsequent_values() {
            assert_eq!(tuple_up!(%"foo", "bar"), (Split("foo"), "bar"));
        }

        #[test]
        fn percent_shortcut_with_preceeding_values() {
            assert_eq!(tuple_up!("foo", %"bar"), ("foo", Split("bar")));
        }

        #[test]
        fn percent_shortcut_with_multiple_values() {
            assert_eq!(
                tuple_up!(%"foo", "bar", %"baz"),
                (Split("foo"), ("bar", Split("baz")))
            );
        }
    }
}