1use std::error::Error;
2use std::fmt;
3
4#[derive(Clone, Debug)]
6pub enum CliErrorKind {
7 MissingArgument(String),
9 MissingParameter(String, usize),
11 ParseCommandLine,
13 Inner,
15}
16
17#[derive(Debug)]
22pub struct CliError {
23 pub source: Option<Box<dyn Error>>,
25 pub kind: CliErrorKind,
27}
28
29impl CliError {
30 pub fn new_inner(source: Box<dyn Error>) -> Self {
41 CliError {
42 source: Some(source),
43 kind: CliErrorKind::Inner,
44 }
45 }
46
47 pub fn new_kind(kind: CliErrorKind) -> Self {
58 CliError { source: None, kind }
59 }
60}
61
62impl Error for CliError {
63 fn source(&self) -> Option<&(dyn Error + 'static)> {
64 self.source.as_deref()
65 }
66}
67
68impl CliErrorKind {
69 pub fn into_boxed_error(self) -> Box<dyn Error> {
70 let error: CliError = self.into();
71 error.into()
72 }
73}
74
75impl fmt::Display for CliErrorKind {
76 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77 match self {
78 CliErrorKind::MissingArgument(arg) =>
79 write!(f, "Required argument '{}' not provided. Use --{} <value> to specify it.", arg, arg),
80 CliErrorKind::MissingParameter(parameter, position) =>
81 write!(f, "Missing parameter for '{}' at position {}. Expected: --{} <value1> <value2> ...", parameter, position, parameter),
82 CliErrorKind::ParseCommandLine =>
83 write!(f, "Failed to parse command line. Ensure arguments are properly formatted with - or -- prefixes."),
84 CliErrorKind::Inner =>
85 write!(f, "Internal error occurred during argument processing"),
86 }
87 }
88}
89
90impl fmt::Display for CliError {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 write!(f, "{}", self.kind)
93 }
94}
95
96impl From<CliErrorKind> for CliError {
97 fn from(kind: CliErrorKind) -> Self {
98 Self::new_kind(kind)
99 }
100}
101
102pub fn from_error<T>(error: T) -> CliError
103where
104 T: Error + Send + Sync + 'static,
105{
106 CliError::new_inner(Box::new(error))
107}
108
109macro_rules! impl_from_error {
110 ($($error_type:ty),+ $(,)?) => {
111 $(
112 impl From<$error_type> for CliError {
113 fn from(error: $error_type) -> Self {
114 from_error(error)
115 }
116 }
117 )+
118 };
119}
120
121impl_from_error!(
122 std::io::Error,
123 std::net::AddrParseError,
124 std::num::ParseIntError,
125 std::str::ParseBoolError,
126 std::char::ParseCharError,
127 std::string::ParseError,
128 std::num::ParseFloatError,
129);
130
131impl From<Box<dyn Error>> for CliError {
132 fn from(error: Box<dyn Error>) -> Self {
133 Self::new_inner(error)
134 }
135}