use core::{
error::Error as StdError,
fmt::{self, Display, Formatter},
str::{self, FromStr},
};
use debate_parser::Arg;
use crate::util::arg_as_str;
#[derive(Debug, Clone, Copy)]
pub struct RequiredError;
impl Display for RequiredError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "command-line parameter required an argument")
}
}
impl StdError for RequiredError {
fn description(&self) -> &str {
"command-line parameter required an argument"
}
}
pub trait Error<'arg> {
fn needs_arg() -> Self;
fn got_arg(argument: &'arg Arg) -> Self;
fn got_additional_instance() -> Self;
fn invalid_utf8(argument: &'arg Arg) -> Self;
fn should_be(argument: &'arg Arg, expected: &'static [&'static str]) -> Self;
fn parse_error(argument: &'arg str, message: impl Display) -> Self;
fn byte_parse_error(argument: &'arg Arg, message: impl Display) -> Self;
fn custom(message: impl Display) -> Self;
}
pub trait ArgAccess<'arg> {
fn with<T, E>(self, op: impl FnOnce(&'arg Arg) -> Result<T, E>) -> Result<T, E>
where
E: Error<'arg>;
}
pub trait Parameter<'arg>: Sized {
#[inline]
fn absent() -> Result<Self, RequiredError> {
Err(RequiredError)
}
#[inline]
fn arg<E: Error<'arg>>(argument: &'arg Arg) -> Result<Self, E> {
Err(E::got_arg(argument))
}
fn present<E: Error<'arg>>(argument: impl ArgAccess<'arg>) -> Result<Self, E>;
#[inline]
fn add_arg<E: Error<'arg>>(&mut self, argument: &'arg Arg) -> Result<(), E> {
Err(E::got_arg(argument))
}
fn add_present<E: Error<'arg>>(&mut self, argument: impl ArgAccess<'arg>) -> Result<(), E>;
}
pub trait PositionalParameter<'arg>: Sized {
#[inline]
fn absent() -> Result<Self, RequiredError> {
Err(RequiredError)
}
fn arg<E: Error<'arg>>(argument: &'arg Arg) -> Result<Self, E>;
fn add_arg<E: Error<'arg>>(&mut self, argument: &'arg Arg) -> Result<(), E>;
}
impl<'arg, T: PositionalParameter<'arg>> Parameter<'arg> for T {
#[inline]
fn absent() -> Result<Self, RequiredError> {
PositionalParameter::absent()
}
#[inline]
fn arg<E: Error<'arg>>(argument: &'arg Arg) -> Result<Self, E> {
PositionalParameter::arg(argument)
}
#[inline]
fn present<E: Error<'arg>>(argument: impl ArgAccess<'arg>) -> Result<Self, E> {
argument.with(PositionalParameter::arg)
}
#[inline]
fn add_arg<E: Error<'arg>>(&mut self, argument: &'arg Arg) -> Result<(), E> {
PositionalParameter::add_arg(self, argument)
}
#[inline]
fn add_present<E: Error<'arg>>(&mut self, argument: impl ArgAccess<'arg>) -> Result<(), E> {
argument.with(|arg| PositionalParameter::add_arg(self, arg))
}
}
pub trait Value<'arg>: Sized {
fn from_arg<E: Error<'arg>>(arg: &'arg Arg) -> Result<Self, E>;
}
impl<'arg, T> PositionalParameter<'arg> for T
where
T: Value<'arg>,
{
#[inline]
fn arg<E: Error<'arg>>(argument: &'arg Arg) -> Result<Self, E> {
Value::from_arg(argument)
}
#[inline]
fn add_arg<E: Error<'arg>>(&mut self, _arg: &'arg Arg) -> Result<(), E> {
Err(E::got_additional_instance())
}
}
pub trait ParsedValue: FromStr {}
impl<'arg, T> Value<'arg> for T
where
T: ParsedValue,
T::Err: Display,
{
fn from_arg<E: Error<'arg>>(arg: &'arg Arg) -> Result<Self, E> {
let arg = arg_as_str(arg)?;
arg.parse().map_err(|err| E::parse_error(arg, err))
}
}