cargo_emit/
pair.rs

1/// Emits a `$key`/`$value` pair to Cargo based on [build script outputs].
2///
3/// This is equivalent to:
4///
5/// ```
6/// println!("cargo:$key=$value");
7/// ```
8///
9/// This is the base macro upon which the other macros are built.
10///
11/// # Examples
12///
13/// This can be used to emit arbitrary user-defined metadata.
14///
15/// ```
16/// cargo_emit::pair!("root", "/path/to/root");
17/// ```
18///
19/// or, in case you want it to emit to a custom stream:
20///
21/// ```
22/// let mut stdout = std::io::stdout();
23/// cargo_emit::pair!(
24///     to: stdout,
25///     "root", "/path/to/root"
26/// );
27/// ```
28///
29/// The `$key` and `$value` parameters get concatenated into a single formatting
30/// string. Formatting runtime values can be done by passing subsequent values.
31///
32/// ```
33/// let name = "foo";
34/// cargo_emit::pair!("{lib}dir", "/path/to/{lib}", lib = name);
35/// ```
36///
37/// [build script outputs]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script
38#[macro_export]
39macro_rules! pair {
40    (to: $stream:expr, $key:expr, $value:expr $(, $($args:tt)*)?) => {{
41        #[allow(unused_imports)]
42        use std::{fmt::Write as _, io::Write as _};
43
44        #[allow(clippy::explicit_write)]
45        writeln!($stream, concat!("cargo:", $key, "=", $value) $(, $($args)*)?).unwrap()
46    }};
47    ($key:expr, $value:expr $(, $($args:tt)*)?) => {
48        $crate::pair!(to: std::io::stdout(), $key, $value $(, $($args)*)?);
49    };
50}
51
52#[cfg(test)]
53mod tests {
54    #[test]
55    fn single_literal() {
56        insta::assert_display_snapshot!(
57            crate::capture_output(|output| {
58                crate::pair!(
59                    to: output,
60                    "KEY", "VALUE"
61                );
62            }),
63            @"cargo:KEY=VALUE\n"
64        );
65    }
66
67    #[test]
68    fn single_with_key_formatted_by_index() {
69        insta::assert_display_snapshot!(
70            crate::capture_output(|output| {
71                crate::pair!(
72                    to: output,
73                    "{}", "VALUE", "KEY"
74                );
75            }),
76            @"cargo:KEY=VALUE\n"
77        );
78    }
79
80    #[test]
81    fn single_with_key_formatted_by_name() {
82        insta::assert_display_snapshot!(
83            crate::capture_output(|output| {
84                crate::pair!(
85                    to: output,
86                    "{key}", "VALUE", key = "KEY"
87                );
88            }),
89            @"cargo:KEY=VALUE\n"
90        );
91    }
92
93    #[test]
94    fn single_with_value_formatted_by_index() {
95        insta::assert_display_snapshot!(
96            crate::capture_output(|output| {
97                crate::pair!(
98                    to: output,
99                    "KEY", "{}", "VALUE"
100                );
101            }),
102            @"cargo:KEY=VALUE\n"
103        );
104    }
105
106    #[test]
107    fn single_with_value_formatted_by_name() {
108        insta::assert_display_snapshot!(
109            crate::capture_output(|output| {
110                crate::pair!(
111                    to: output,
112                    "KEY", "{value}", value = "VALUE"
113                );
114            }),
115            @"cargo:KEY=VALUE\n"
116        );
117    }
118
119    #[test]
120    fn single_with_key_and_value_formatted_by_index() {
121        insta::assert_display_snapshot!(
122            crate::capture_output(|output| {
123                crate::pair!(
124                    to: output,
125                    "{}", "{}", "KEY", "VALUE"
126                );
127            }),
128            @"cargo:KEY=VALUE\n"
129        );
130    }
131
132    #[test]
133    fn single_with_key_and_value_formatted_by_name() {
134        insta::assert_display_snapshot!(
135            crate::capture_output(|output| {
136                crate::pair!(
137                    to: output,
138                    "{key}", "{value}", key = "KEY", value = "VALUE"
139                );
140            }),
141            @"cargo:KEY=VALUE\n"
142        );
143    }
144}