use std::{ffi::OsString, fmt::{Display, self}, ops::Deref};
#[derive(Debug, Default, Clone)]
pub struct MkArgs(Vec<OsString>);
impl MkArgs {
pub fn new() -> MkArgs {
Default::default()
}
pub fn with(mut self, arg: impl Into<OsString>) -> Self {
self.push(arg);
self
}
pub fn with_pair(mut self, arg1: impl Into<OsString>, arg2: impl Into<OsString>) -> Self {
self.push_pair(arg1, arg2);
self
}
pub fn with_append(mut self, args: MkArgs) -> Self {
self.append(args);
self
}
pub fn with_cond(mut self, arg: impl Into<OsString>, cond: bool) -> Self {
if cond {
self.push(arg);
}
self
}
pub fn with_pair_cond(mut self, arg1: impl Into<OsString>, arg2: impl Into<OsString>, cond: bool) -> Self {
if cond {
self.push_pair(arg1, arg2);
}
self
}
pub fn with_append_cond(mut self, args: MkArgs, cond: bool) -> Self {
if cond {
self.append(args);
}
self
}
pub fn push(&mut self, arg: impl Into<OsString>) {
self.0.push(arg.into())
}
pub fn push_pair(&mut self, arg1: impl Into<OsString>, arg2: impl Into<OsString>) {
self.0.push(arg1.into());
self.0.push(arg2.into());
}
pub fn append(&mut self, args: impl Into<MkArgs>) {
self.0.extend(args.into().0.into_iter());
}
pub fn into_inner(self) -> Vec<OsString> {
self.0
}
pub fn as_slice(&self) -> &[OsString] {
self.0.as_slice()
}
pub fn into_strings(self) -> Result<Vec<String>, OsString> {
self.0.into_iter().map(|a| a.into_string()).collect()
}
}
impl Deref for MkArgs {
type Target = [OsString];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl From<MkArgs> for Vec<OsString> {
fn from(args: MkArgs) -> Vec<OsString> {
args.into_inner()
}
}
impl TryFrom<MkArgs> for Vec<String> {
type Error = OsString;
fn try_from(args: MkArgs) -> Result<Vec<String>, OsString> {
args.into_strings()
}
}
impl From<Vec<OsString>> for MkArgs {
fn from(args: Vec<OsString>) -> MkArgs {
MkArgs(args)
}
}
impl<'i> From<&'i [OsString]> for MkArgs {
fn from(args: &'i [OsString]) -> MkArgs {
MkArgs(args.to_vec())
}
}
impl Display for MkArgs {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
#[macro_export]
macro_rules! mkargs {
($($arg:expr),*) => {{
use std::ffi::OsString;
let args: &[OsString] = &[$(Into::<OsString>::into($arg)),*];
$crate::MkArgs::from(args)
}};
}
#[cfg(target_family = "unix")]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_echo() {
use std::process::Command;
let world = "world".to_string();
let mut args = mkargs!["hello", world];
args.push_pair("foo", "bar");
let out = Command::new("echo")
.args(&*args)
.output()
.expect("echo command failed to start");
assert_eq!(out.stdout, b"hello world foo bar\n");
}
}