use crate::{
ArgErrCtx, ArgErrKind, ColorMode, FromRead, Reader,
arg_into::ArgInto,
err::{ArgError, Result},
from_arg::FromArg,
};
pub fn key_mval_arg<'a, K, V>(
arg: &'a str,
sep: char,
) -> Result<(K, Option<V>)>
where
K: FromArg<'a>,
V: FromArg<'a>,
{
let Some((k, v)) = arg.split_once(sep) else {
return Ok((K::from_arg(arg)?, None));
};
Ok((
K::from_arg(k).map_err(|e| e.shift_span(0, arg.to_string()))?,
Some(V::from_arg(v).map_err(|e| {
e.shift_span(k.len() + sep.len_utf8(), arg.to_string())
})?),
))
}
pub fn key_val_arg<'a, K, V>(arg: &'a str, sep: char) -> Result<(K, V)>
where
K: FromArg<'a>,
V: FromArg<'a>,
{
let Some((k, v)) = arg.split_once(sep) else {
return ArgError::new(ArgErrCtx {
args: vec![arg.into()],
error_span: (0..arg.len()).into(),
inline_msg: Some(format!("Missing separator `{sep}`.").into()),
long_msg: Some(format!("Missing separator `{sep}` for key value pair.").into()),
hint: Some(format!("Use the separator `{sep}` to split the argument into key and value.").into()),
..ArgErrCtx::new(ArgErrKind::NoValue)
}).err();
};
Ok((
K::from_arg(k).map_err(|e| e.shift_span(0, arg.to_string()))?,
V::from_arg(v).map_err(|e| {
e.shift_span(k.len() + sep.len_utf8(), arg.to_string())
})?,
))
}
pub fn bool_arg(t: &str, f: &str, arg: &str) -> Result<bool> {
let lower = arg.to_lowercase();
if lower == t {
Ok(true)
} else if lower == f {
Ok(false)
} else {
ArgError::new(ArgErrCtx {
args: vec![arg.into()],
error_span: (0..arg.len()).into(),
inline_msg: Some("Invalid value.".into()),
long_msg: Some(format!("Invalid value `{arg}`").into()),
hint: Some(format!("Expected `{t}` or `{f}`").into()),
..ArgErrCtx::new(ArgErrKind::FailedToParse)
})
.err()
}
}
pub fn opt_bool_arg(
t: &str,
f: &str,
n: &str,
arg: &str,
) -> Result<Option<bool>> {
let lower = arg.to_lowercase();
if lower == t {
Ok(Some(true))
} else if lower == f {
Ok(Some(false))
} else if lower == n {
Ok(None)
} else {
ArgError::new(ArgErrCtx {
args: vec![arg.into()],
error_span: (0..arg.len()).into(),
inline_msg: Some("Invalid value.".into()),
long_msg: Some(format!("Invalid value `{arg}`").into()),
hint: Some(format!("Expected `{t}`, `{f}` or `{n}`").into()),
color: ColorMode::default(),
..ArgErrCtx::new(ArgErrKind::FailedToParse)
})
.err()
}
}
#[inline(always)]
pub fn parse_arg<'a, T>(arg: &'a str) -> Result<T>
where
T: FromArg<'a>,
{
arg.arg_into()
}
#[inline(always)]
pub fn key_arg<'a, T>(arg: &'a str, sep: char) -> Result<T>
where
T: FromArg<'a>,
{
Ok(key_mval_arg::<_, &str>(arg, sep)?.0)
}
#[inline(always)]
pub fn val_arg<'a, T>(arg: &'a str, sep: char) -> Result<T>
where
T: FromArg<'a>,
{
Ok(key_val_arg::<&str, _>(arg, sep)?.1)
}
#[inline(always)]
pub fn mval_arg<'a, T>(arg: &'a str, sep: char) -> Result<Option<T>>
where
T: FromArg<'a>,
{
Ok(key_mval_arg::<&str, _>(arg, sep)?.1)
}
pub fn try_set_arg_with<'a, T>(
res: &mut Option<T>,
arg: &'a str,
f: impl FnOnce(&'a str) -> Result<T>,
) -> Result<()> {
if res.is_some() {
ArgError::too_many_arguments(
"Argument sets value that can be set only once.",
arg,
)
.err()
} else {
*res = Some(f(arg)?);
Ok(())
}
}
pub fn try_set_arg<'a, T: FromArg<'a>>(
res: &mut Option<T>,
arg: &'a str,
) -> Result<()> {
try_set_arg_with(res, arg, T::from_arg)
}
pub fn split_arg<'a, T: FromArg<'a>>(
arg: &'a str,
sep: &str,
) -> Result<Vec<T>> {
let mut r = vec![];
for s in arg.split(sep) {
r.push(s.arg_into()?);
}
Ok(r)
}
pub fn arg_list<T: FromRead>(arg: &str, sep: &str) -> Result<Vec<T>> {
let mut res = vec![];
let mut reader: Reader = arg.into();
loop {
let (item, _) = T::from_read(&mut reader, &"".into())?;
res.push(item);
if reader.peek()?.is_none() {
return Ok(res);
}
reader.expect(sep)?;
}
}