use std::error::Error;
use std::fmt;
#[derive(Clone, Debug)]
pub enum CliErrorKind {
MissingArgument(String),
MissingParameter(String, usize),
ParseCommandLine,
Inner,
}
#[derive(Debug)]
pub struct CliError {
pub source: Option<Box<dyn Error>>,
pub kind: CliErrorKind,
}
impl CliError {
pub fn new_inner(source: Box<dyn Error>) -> Self {
CliError {
source: Some(source),
kind: CliErrorKind::Inner,
}
}
pub fn new_kind(kind: CliErrorKind) -> Self {
CliError { source: None, kind }
}
}
impl Error for CliError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.source.as_deref()
}
}
impl CliErrorKind {
pub fn into_boxed_error(self) -> Box<dyn Error> {
let error: CliError = self.into();
error.into()
}
}
impl fmt::Display for CliErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
CliErrorKind::MissingArgument(arg) =>
write!(f, "Required argument '{}' not provided. Use --{} <value> to specify it.", arg, arg),
CliErrorKind::MissingParameter(parameter, position) =>
write!(f, "Missing parameter for '{}' at position {}. Expected: --{} <value1> <value2> ...", parameter, position, parameter),
CliErrorKind::ParseCommandLine =>
write!(f, "Failed to parse command line. Ensure arguments are properly formatted with - or -- prefixes."),
CliErrorKind::Inner =>
write!(f, "Internal error occurred during argument processing"),
}
}
}
impl fmt::Display for CliError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.kind)
}
}
impl From<CliErrorKind> for CliError {
fn from(kind: CliErrorKind) -> Self {
Self::new_kind(kind)
}
}
pub fn from_error<T>(error: T) -> CliError
where
T: Error + Send + Sync + 'static,
{
CliError::new_inner(Box::new(error))
}
macro_rules! impl_from_error {
($($error_type:ty),+ $(,)?) => {
$(
impl From<$error_type> for CliError {
fn from(error: $error_type) -> Self {
from_error(error)
}
}
)+
};
}
impl_from_error!(
std::io::Error,
std::net::AddrParseError,
std::num::ParseIntError,
std::str::ParseBoolError,
std::char::ParseCharError,
std::string::ParseError,
std::num::ParseFloatError,
);
impl From<Box<dyn Error>> for CliError {
fn from(error: Box<dyn Error>) -> Self {
Self::new_inner(error)
}
}