1use std::{ffi::OsString, fmt::{Display, self}, ops::Deref};
20
21#[derive(Debug, Default, Clone)]
23pub struct MkArgs(Vec<OsString>);
24
25impl MkArgs {
26 pub fn new() -> MkArgs {
28 Default::default()
29 }
30
31 pub fn with(mut self, arg: impl Into<OsString>) -> Self {
33 self.push(arg);
34 self
35 }
36
37 pub fn with_pair(mut self, arg1: impl Into<OsString>, arg2: impl Into<OsString>) -> Self {
39 self.push_pair(arg1, arg2);
40 self
41 }
42
43 pub fn with_append(mut self, args: MkArgs) -> Self {
45 self.append(args);
46 self
47 }
48
49 pub fn with_cond(mut self, arg: impl Into<OsString>, cond: bool) -> Self {
51 if cond {
52 self.push(arg);
53 }
54 self
55 }
56
57 pub fn with_pair_cond(mut self, arg1: impl Into<OsString>, arg2: impl Into<OsString>, cond: bool) -> Self {
59 if cond {
60 self.push_pair(arg1, arg2);
61 }
62 self
63 }
64
65 pub fn with_append_cond(mut self, args: MkArgs, cond: bool) -> Self {
67 if cond {
68 self.append(args);
69 }
70 self
71 }
72
73 pub fn push(&mut self, arg: impl Into<OsString>) {
75 self.0.push(arg.into())
76 }
77
78 pub fn push_pair(&mut self, arg1: impl Into<OsString>, arg2: impl Into<OsString>) {
80 self.0.push(arg1.into());
81 self.0.push(arg2.into());
82 }
83
84 pub fn append(&mut self, args: impl Into<MkArgs>) {
86 self.0.extend(args.into().0.into_iter());
87 }
88
89 pub fn into_inner(self) -> Vec<OsString> {
91 self.0
92 }
93
94 pub fn as_slice(&self) -> &[OsString] {
96 self.0.as_slice()
97 }
98
99 pub fn into_strings(self) -> Result<Vec<String>, OsString> {
103 self.0.into_iter().map(|a| a.into_string()).collect()
104 }
105}
106
107impl Deref for MkArgs {
108 type Target = [OsString];
109
110 fn deref(&self) -> &Self::Target {
111 self.as_slice()
112 }
113}
114
115impl From<MkArgs> for Vec<OsString> {
116 fn from(args: MkArgs) -> Vec<OsString> {
117 args.into_inner()
118 }
119}
120
121impl TryFrom<MkArgs> for Vec<String> {
122 type Error = OsString;
123
124 fn try_from(args: MkArgs) -> Result<Vec<String>, OsString> {
125 args.into_strings()
126 }
127}
128
129impl From<Vec<OsString>> for MkArgs {
130 fn from(args: Vec<OsString>) -> MkArgs {
131 MkArgs(args)
132 }
133}
134
135impl<'i> From<&'i [OsString]> for MkArgs {
136 fn from(args: &'i [OsString]) -> MkArgs {
137 MkArgs(args.to_vec())
138 }
139}
140
141impl Display for MkArgs {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
143 write!(f, "{:?}", self.0)
144 }
145}
146
147#[macro_export]
148macro_rules! mkargs {
149 ($($arg:expr),*) => {{
150 use std::ffi::OsString;
151 let args: &[OsString] = &[$(Into::<OsString>::into($arg)),*];
152 $crate::MkArgs::from(args)
153 }};
154}
155
156#[cfg(target_family = "unix")]
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn test_echo() {
163 use std::process::Command;
164
165 let world = "world".to_string();
166 let mut args = mkargs!["hello", world];
167
168 args.push_pair("foo", "bar");
169
170 let out = Command::new("echo")
171 .args(&*args)
172 .output()
173 .expect("echo command failed to start");
174
175 assert_eq!(out.stdout, b"hello world foo bar\n");
176 }
177}