1use std::process::Command;
2
3pub trait AsCommand {
5 fn as_command(&self) -> Command;
30}
31
32impl AsCommand for [&str] {
33 fn as_command(&self) -> Command {
34 let mut command = Command::new(self[0]);
35 command.args(&self[1..]);
36 command
37 }
38}
39
40impl AsCommand for [String] {
41 fn as_command(&self) -> Command {
42 let parts: Vec<&str> = self.iter().map(|s| s.as_str()).collect();
43 parts.as_command()
44 }
45}
46
47impl AsCommand for &[&str] {
48 fn as_command(&self) -> Command {
49 self[..].as_command()
50 }
51}
52
53impl AsCommand for &[String] {
54 fn as_command(&self) -> Command {
55 self[..].as_command()
56 }
57}
58
59impl<const N: usize> AsCommand for [&str; N] {
60 fn as_command(&self) -> Command {
61 self.as_slice().as_command()
62 }
63}
64
65impl<const N: usize> AsCommand for [String; N] {
66 fn as_command(&self) -> Command {
67 self.as_slice().as_command()
68 }
69}
70
71impl AsCommand for Vec<&str> {
72 fn as_command(&self) -> Command {
73 self.as_slice().as_command()
74 }
75}
76
77impl AsCommand for Vec<String> {
78 fn as_command(&self) -> Command {
79 self.as_slice().as_command()
80 }
81}
82
83impl AsCommand for str {
84 fn as_command(&self) -> Command {
85 let parts = shell_words::split(self).expect("Failed to parse command string");
86 parts.as_command()
87 }
88}
89
90impl AsCommand for &str {
91 fn as_command(&self) -> Command {
92 let parts = shell_words::split(self).expect("Failed to parse command string");
93 parts.as_command()
94 }
95}
96
97impl AsCommand for String {
98 fn as_command(&self) -> Command {
99 self.as_str().as_command()
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 fn check_command(cmd: &Command, expected_program: &str, expected_args: &[&str]) {
115 assert_eq!(cmd.get_program().to_str().unwrap(), expected_program);
116 let args: Vec<&str> = cmd.get_args().map(|a| a.to_str().unwrap()).collect();
117 assert_eq!(args, expected_args);
118 }
119
120 #[test]
121 fn test_as_command_from_str_slice_reference() {
122 let cmd: &[&str] = &["echo", "Hello, world!"];
123 let cmd = cmd.as_command();
124 check_command(&cmd, "echo", &["Hello, world!"]);
125 }
126
127 #[test]
128 fn test_as_command_from_string_slice_reference() {
129 let cmd: &[&str] = &["echo", "Hello, world!"];
130 let cmd = cmd.as_command();
131 check_command(&cmd, "echo", &["Hello, world!"]);
132 }
133
134 #[test]
135 fn test_as_command_from_str_array() {
136 let cmd: [&str; 2] = ["echo", "Hello, world!"];
137 let cmd = cmd.as_command();
138 check_command(&cmd, "echo", &["Hello, world!"]);
139 }
140
141 #[test]
142 fn test_as_command_from_string_array() {
143 let cmd: [String; 2] = [String::from("echo"), String::from("Hello, world!")];
144 let cmd = cmd.as_command();
145 check_command(&cmd, "echo", &["Hello, world!"]);
146 }
147
148 #[test]
149 fn test_as_command_from_str_vector() {
150 let cmd: Vec<&str> = vec!["echo", "Hello, world!"];
151 let cmd = cmd.as_command();
152 check_command(&cmd, "echo", &["Hello, world!"]);
153 }
154
155 #[test]
156 fn test_as_command_from_string_vector() {
157 let cmd: Vec<String> = vec![String::from("echo"), String::from("Hello, world!")];
158 let cmd = cmd.as_command();
159 check_command(&cmd, "echo", &["Hello, world!"]);
160 }
161
162 #[test]
163 fn test_as_command_from_str() {
164 let cmd: &str = "echo \"Hello, world!\"";
165 let cmd = cmd.as_command();
166 check_command(&cmd, "echo", &["Hello, world!"]);
167 }
168
169 #[test]
170 fn test_as_command_from_string() {
171 let cmd: String = "echo \"Hello, world!\"".into();
172 let cmd = cmd.as_command();
173 check_command(&cmd, "echo", &["Hello, world!"]);
174 }
175}