1use std::fmt;
2use std::num::{ParseFloatError, ParseIntError};
3
4use crate::util::Flag;
5
6#[derive(Debug)]
11pub struct Error {
12 inner: ErrorInner,
13 source: Option<Box<dyn std::error::Error + Sync + Send + 'static>>,
14}
15
16impl Error {
17 pub fn with_source(
35 self,
36 source: impl std::error::Error + Sync + Send + 'static,
37 ) -> Self {
38 Error { source: Some(Box::new(source)), ..self }
39 }
40
41 pub fn no_value() -> Self {
43 ErrorInner::NoValue.into()
44 }
45
46 pub fn is_no_value(&self) -> bool {
48 self.inner == ErrorInner::NoValue
49 }
50
51 pub fn missing_value() -> Self {
53 ErrorInner::MissingValue.into()
54 }
55
56 pub fn is_missing_value(&self) -> bool {
58 self.inner == ErrorInner::MissingValue
59 }
60
61 pub fn early_exit() -> Self {
63 ErrorInner::EarlyExit.into()
64 }
65
66 pub fn is_early_exit(&self) -> bool {
68 self.inner == ErrorInner::EarlyExit
69 }
70
71 pub fn unexpected_value(got: impl ToString, expected: impl ToString) -> Self {
73 ErrorInner::UnexpectedValue {
74 got: got.to_string(),
75 expected: expected.to_string(),
76 }
77 .into()
78 }
79
80 pub fn missing_argument(arg: impl ToString) -> Self {
82 ErrorInner::MissingArgument { arg: arg.to_string() }.into()
83 }
84
85 pub fn in_argument(flag: &Flag) -> Self {
87 ErrorInner::InArgument(flag.first_to_string()).into()
88 }
89
90 pub fn in_subcommand(cmd: impl ToString) -> Self {
92 ErrorInner::InSubcommand(cmd.to_string()).into()
93 }
94}
95
96impl From<ErrorInner> for Error {
97 fn from(inner: ErrorInner) -> Self {
98 Error { inner, source: None }
99 }
100}
101
102#[derive(Debug, PartialEq)]
104pub enum ErrorInner {
105 NoValue,
108
109 MissingValue,
112
113 IncompleteValue(usize),
115
116 EarlyExit,
118
119 InArgument(String),
122
123 InSubcommand(String),
126
127 UnexpectedValue {
129 got: String,
131 expected: String,
134 },
135
136 TooManyValues {
138 max: usize,
140 count: usize,
142 },
143
144 WrongNumberOfValues {
146 expected: usize,
148 got: usize,
150 },
151
152 MissingArgument {
154 arg: String,
156 },
157
158 UnexpectedArgument {
160 arg: String,
162 },
163
164 TooManyArgOccurrences {
166 arg: String,
168 max: Option<u32>,
170 },
171
172 ParseIntError(ParseIntError),
174
175 ParseFloatError(ParseFloatError),
177}
178
179impl From<ParseIntError> for Error {
180 fn from(e: ParseIntError) -> Self {
181 ErrorInner::ParseIntError(e).into()
182 }
183}
184impl From<ParseFloatError> for Error {
185 fn from(e: ParseFloatError) -> Self {
186 ErrorInner::ParseFloatError(e).into()
187 }
188}
189
190impl std::error::Error for Error {
191 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
192 match &self.source {
193 Some(source) => Some(&**source as &(dyn std::error::Error + 'static)),
194 None => None,
195 }
196 }
197}
198
199impl fmt::Display for Error {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 match &self.inner {
202 ErrorInner::NoValue => write!(f, "no value"),
203 ErrorInner::MissingValue => write!(f, "missing value"),
204 ErrorInner::IncompleteValue(part) => {
205 write!(f, "missing part {} of value", part)
206 }
207 ErrorInner::EarlyExit => write!(f, "early exit"),
208 ErrorInner::InArgument(opt) => write!(f, "in `{}`", opt.escape_debug()),
209 ErrorInner::InSubcommand(cmd) => {
210 write!(f, "in subcommand {}", cmd.escape_debug())
211 }
212 ErrorInner::UnexpectedValue { expected, got } => {
213 write!(
214 f,
215 "unexpected value `{}`, expected {}",
216 got.escape_debug(),
217 expected.escape_debug()
218 )
219 }
220 ErrorInner::UnexpectedArgument { arg } => {
221 write!(f, "unexpected argument `{}`", arg.escape_debug())
222 }
223 ErrorInner::TooManyValues { max, count } => {
224 write!(f, "too many values, expected at most {}, got {}", max, count)
225 }
226 ErrorInner::WrongNumberOfValues { expected, got } => {
227 write!(f, "wrong number of values, expected {}, got {}", expected, got)
228 }
229 ErrorInner::MissingArgument { arg } => {
230 write!(f, "required {} was not provided", arg)
231 }
232 ErrorInner::TooManyArgOccurrences { arg, max } => {
233 if let Some(max) = max {
234 write!(
235 f,
236 "{} was used too often, it can be used at most {} times",
237 arg, max
238 )
239 } else {
240 write!(f, "{} was used too often", arg)
241 }
242 }
243
244 ErrorInner::ParseIntError(e) => write!(f, "{}", e),
245 ErrorInner::ParseFloatError(e) => write!(f, "{}", e),
246 }
247 }
248}