1use std::ffi::OsStr;
2use std::fmt::Display;
3use std::num::ParseFloatError;
4use std::num::ParseIntError;
5use std::ops::Deref;
6use std::thread::AccessError;
7
8use crate::str::display_of_osstr;
9use crate::Uid;
10
11pub type Result<T> = std::result::Result<T, Error>;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub enum Kind {
15 MissingValue,
16
17 PosRequired,
18
19 OptRequired,
20
21 CmdRequired,
22
23 OptionNotFound,
24
25 ExtractValue,
26
27 RawValParse,
28
29 Arg,
30
31 IndexParse,
32
33 CreateStrParse,
34
35 Failure,
36
37 Error,
38
39 NoParserMatched,
40
41 UnexceptedPos,
42
43 ThreadLocalAccess,
44}
45
46impl Kind {
47 const fn desp(&self) -> Option<&'static str> {
48 match self {
49 Kind::UnexceptedPos => Some("can not insert Pos@1 if Cmd exist"),
50 Kind::ThreadLocalAccess => Some("failed access thread local variable"),
51 Kind::NoParserMatched => Some("all parser passed to `getopt!` match failed"),
52 _ => None,
53 }
54 }
55}
56
57#[derive(Debug, Clone)]
58pub struct Error {
59 uid: Option<Uid>,
60
61 kind: Kind,
62
63 desp: Option<String>,
64
65 cause: Option<Box<Error>>,
66}
67
68impl std::error::Error for Error {
69 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
70 self.cause
71 .as_ref()
72 .map(|v| v.deref() as &(dyn std::error::Error + 'static))
73 }
74}
75
76impl Display for Error {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 let desp = self.desp.as_deref().or(self.kind.desp());
79
80 assert!(
81 desp.is_some(),
82 "need description for error `{:?}`",
83 self.kind
84 );
85
86 if let Some(uid) = self.uid {
87 write!(f, "{} (uid = {})", desp.unwrap(), uid)
88 } else {
89 write!(f, "{}", desp.unwrap())
90 }
91 }
92}
93
94impl Error {
95 pub fn new(kind: Kind) -> Self {
96 Self {
97 kind,
98 uid: None,
99 desp: None,
100 cause: None,
101 }
102 }
103
104 pub fn cause(self, error: Self) -> Self {
105 error.cause_by(self)
106 }
107
108 pub fn cause_by(mut self, cause_by: Self) -> Self {
109 let _ = self.cause.insert(Box::new(cause_by));
110 self
111 }
112
113 pub fn with_uid(mut self, uid: Uid) -> Self {
114 self.uid = Some(uid);
115 self
116 }
117
118 pub fn with_desp(mut self, desp: String) -> Self {
119 self.desp = Some(desp);
120 self
121 }
122
123 pub fn uid(&self) -> Option<Uid> {
124 self.uid
125 }
126
127 pub fn kind(&self) -> &Kind {
128 &self.kind
129 }
130
131 pub fn caused_by(&self) -> Option<&Error> {
132 self.cause.as_deref()
133 }
134
135 pub fn is_failure(&self) -> bool {
137 let kind = &self.kind;
138
139 matches!(
140 kind,
141 Kind::RawValParse
142 | Kind::Failure
143 | Kind::ExtractValue
144 | Kind::OptionNotFound
145 | Kind::CmdRequired
146 | Kind::PosRequired
147 | Kind::OptRequired
148 | Kind::MissingValue
149 )
150 }
151
152 pub fn unexcepted_pos() -> Self {
154 Self::new(Kind::UnexceptedPos)
155 }
156
157 pub fn thread_local_access() -> Self {
158 Self::new(Kind::ThreadLocalAccess)
159 }
160
161 pub fn no_parser_matched() -> Self {
162 Self::new(Kind::NoParserMatched)
163 }
164
165 pub fn from<E: std::error::Error + Display>(error: E) -> Self {
166 Self::raise_error(error.to_string())
167 }
168
169 pub fn arg(arg: impl Into<String>, hint: impl Into<String>) -> Self {
170 let desp = format!("invalid argument `{}`: {}", arg.into(), hint.into());
171
172 Self::new(Kind::Arg).with_desp(desp)
173 }
174
175 pub fn sp_rawval(val: Option<&OsStr>, hint: impl Into<String>) -> Self {
176 let desp = format!("invalid value `{}`: {}", display_of_osstr(val), hint.into());
177
178 Self::new(Kind::RawValParse).with_desp(desp)
179 }
180
181 pub fn index_parse(pat: impl Into<String>, hint: impl Into<String>) -> Self {
182 let desp = format!("invalid index string `{}`: {}", pat.into(), hint.into());
183
184 Self::new(Kind::IndexParse).with_desp(desp)
185 }
186
187 pub fn create_str(pat: impl Into<String>, hint: impl Into<String>) -> Self {
188 let desp = format!(
189 "invalid option create string `{}`: {}",
190 pat.into(),
191 hint.into()
192 );
193
194 Self::new(Kind::CreateStrParse).with_desp(desp)
195 }
196
197 pub fn raise_error(msg: impl Into<String>) -> Self {
198 Self::new(Kind::Error).with_desp(msg.into())
199 }
200
201 pub fn raise_failure(msg: impl Into<String>) -> Self {
202 Self::new(Kind::Failure).with_desp(msg.into())
203 }
204
205 pub fn sp_missing_value(name: impl Into<String>) -> Self {
206 let desp = format!("missing value for option `{}`", name.into());
207
208 Self::new(Kind::MissingValue).with_desp(desp)
209 }
210
211 pub fn sp_pos_require<S: Into<String>>(names: Vec<S>) -> Self {
212 let names: Vec<_> = names.into_iter().map(Into::into).collect();
213 let desp = match names.len() {
214 1 => {
215 format!("positional `{}` is force required", names[0])
216 }
217 _ => {
218 format!("positional `{}` are force required", names.join(", "))
219 }
220 };
221
222 Self::new(Kind::PosRequired).with_desp(desp)
223 }
224
225 pub fn sp_opt_require<S: Into<String>>(names: Vec<S>) -> Self {
226 let names: Vec<_> = names.into_iter().map(Into::into).collect();
227 let desp = match names.len() {
228 1 => {
229 format!("option `{}` is force required", names[0])
230 }
231 _ => {
232 format!("option `{}` are force required", names.join(", "))
233 }
234 };
235
236 Self::new(Kind::OptRequired).with_desp(desp)
237 }
238
239 pub fn sp_cmd_require<S: Into<String>>(names: Vec<S>) -> Self {
240 let names: Vec<_> = names.into_iter().map(Into::into).collect();
241 let desp = match names.len() {
242 1 => {
243 format!("command `{}` is force required", names[0])
244 }
245 _ => {
246 format!("command `{}` are force required", names.join(", "))
247 }
248 };
249
250 Self::new(Kind::CmdRequired).with_desp(desp)
251 }
252
253 pub fn sp_not_found(name: impl Into<String>) -> Self {
254 let desp = format!("can not find option `{}`", name.into());
255
256 Self::new(Kind::OptionNotFound).with_desp(desp)
257 }
258
259 pub fn sp_extract(msg: impl Into<String>) -> Self {
260 let desp = format!("extract value failed: `{}`", msg.into());
261
262 Self::new(Kind::ExtractValue).with_desp(desp)
263 }
264}
265
266impl From<ParseIntError> for Error {
267 fn from(value: ParseIntError) -> Self {
268 Error::from(value)
269 }
270}
271
272impl From<ParseFloatError> for Error {
273 fn from(value: ParseFloatError) -> Self {
274 Error::from(value)
275 }
276}
277
278impl From<AccessError> for Error {
279 fn from(value: AccessError) -> Self {
280 Error::from(value)
281 }
282}
283
284#[macro_export]
285macro_rules! error {
286 ($($arg:tt)*) => {
287 $crate::Error::raise_error(format!($($arg)*))
288 };
289}
290
291#[macro_export]
292macro_rules! failure {
293 ($($arg:tt)*) => {
294 $crate::Error::raise_failure(format!($($arg)*))
295 };
296}