use std::convert::Infallible;
use std::num::{ParseFloatError, ParseIntError};
pub type ArgResult<T> = Option<Result<T, <T as ArgumentType>::Error>>;
pub type DefaultedArgResult<T> = Result<T, <T as ArgumentType>::Error>;
pub trait ArgumentType: Sized {
type Error;
const CONSUMES: bool = true;
const REPEATABLE: bool = false;
#[allow(clippy::missing_errors_doc)]
fn from_value(val: Option<&str>) -> ArgResult<Self>;
fn default_value() -> Option<Self> {
None
}
}
macro_rules! impl_intrinsics {
( $( $typ:ty, $err:ty $( => $default:block )? );+ $(;)? ) => {
$(
impl ArgumentType for $typ {
type Error = $err;
fn from_value(val: Option<&str>) -> ArgResult<Self> {
val.map(|val| val.parse())
}
$(
fn default_value() -> Option<Self> {
$default
}
)?
}
)+
};
}
impl_intrinsics! {
i8, ParseIntError;
i16, ParseIntError;
i32, ParseIntError;
i64, ParseIntError;
i128, ParseIntError;
isize, ParseIntError;
u8, ParseIntError;
u16, ParseIntError;
u32, ParseIntError;
u64, ParseIntError;
u128, ParseIntError;
usize, ParseIntError;
f32, ParseFloatError;
f64, ParseFloatError;
String, Infallible;
}
impl ArgumentType for bool {
type Error = Infallible;
const CONSUMES: bool = false;
fn from_value(val: Option<&str>) -> ArgResult<Self> {
Some(Ok(if let Some(val) = val {
["true", "1", "t"].contains(&val)
} else {
true
}))
}
fn default_value() -> Option<Self> {
Some(false)
}
}
impl<T: ArgumentType> ArgumentType for Vec<T> {
type Error = T::Error;
const REPEATABLE: bool = true;
fn from_value(val: Option<&str>) -> ArgResult<Self> {
let bits = val?.split(',');
let mut values = Vec::new();
for bit in bits {
values.push(match T::from_value(Some(bit))? {
Ok(t) => t,
Err(e) => return Some(Err(e)),
});
}
Some(Ok(values))
}
}