1#![allow(unused)]
4
5#[cfg(feature = "std")]
6extern crate std;
7
8pub type SysexitsResult<T> = core::result::Result<T, SysexitsError>;
9
10#[allow(non_camel_case_types)]
22#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
23#[repr(u8)]
24pub enum SysexitsError {
25 #[default]
26 EX_OK = 0,
28
29 EX_USAGE = 64,
32
33 EX_DATAERR = 65,
37
38 EX_NOINPUT = 66,
43
44 EX_NOUSER = 67,
48
49 EX_NOHOST = 68,
53
54 EX_UNAVAILABLE = 69,
60
61 EX_SOFTWARE = 70,
66
67 EX_OSERR = 71,
73
74 EX_OSFILE = 72,
78
79 EX_CANTCREAT = 73,
81
82 EX_IOERR = 74,
84
85 EX_TEMPFAIL = 75,
90
91 EX_PROTOCOL = 76,
94
95 EX_NOPERM = 77,
101
102 EX_CONFIG = 78,
104}
105
106impl SysexitsError {
107 pub fn is_success(&self) -> bool {
108 *self == Self::EX_OK
109 }
110
111 pub fn is_failure(&self) -> bool {
112 !self.is_success()
113 }
114
115 pub fn as_u8(&self) -> u8 {
116 *self as u8
117 }
118
119 pub fn as_i32(&self) -> i32 {
120 *self as i32
121 }
122
123 pub fn as_str(&self) -> &'static str {
124 self.name()
125 }
126
127 #[cfg(feature = "std")]
128 pub fn as_exit_code(&self) -> std::process::ExitCode {
129 std::process::ExitCode::from(self.as_u8())
130 }
131
132 #[cfg(feature = "std")]
133 fn as_exit_status(&self) -> Option<std::process::ExitStatus> {
134 match *self {
135 Self::EX_OK => Some(std::process::ExitStatus::default()),
136 _ => None,
137 }
138 }
139
140 pub fn code(&self) -> Option<i32> {
141 Some(self.as_i32())
142 }
143
144 pub fn name(&self) -> &'static str {
145 use SysexitsError::*;
146 match *self {
147 EX_OK => "EX_OK",
148 EX_USAGE => "EX_USAGE",
149 EX_DATAERR => "EX_DATAERR",
150 EX_NOINPUT => "EX_NOINPUT",
151 EX_NOUSER => "EX_NOUSER",
152 EX_NOHOST => "EX_NOHOST",
153 EX_UNAVAILABLE => "EX_UNAVAILABLE",
154 EX_SOFTWARE => "EX_SOFTWARE",
155 EX_OSERR => "EX_OSERR",
156 EX_OSFILE => "EX_OSFILE",
157 EX_CANTCREAT => "EX_CANTCREAT",
158 EX_IOERR => "EX_IOERR",
159 EX_TEMPFAIL => "EX_TEMPFAIL",
160 EX_PROTOCOL => "EX_PROTOCOL",
161 EX_NOPERM => "EX_NOPERM",
162 EX_CONFIG => "EX_CONFIG",
163 }
164 }
165
166 pub fn summary(&self) -> &'static str {
167 use SysexitsError::*;
169 match *self {
170 EX_OK => "successful termination",
171 EX_USAGE => "command line usage error",
172 EX_DATAERR => "data format error",
173 EX_NOINPUT => "cannot open input",
174 EX_NOUSER => "addressee unknown",
175 EX_NOHOST => "host name unknown",
176 EX_UNAVAILABLE => "service unavailable",
177 EX_SOFTWARE => "internal software error",
178 EX_OSERR => "system error",
179 EX_OSFILE => "critical OS file missing",
180 EX_CANTCREAT => "can't create (user) output file",
181 EX_IOERR => "input/output error",
182 EX_TEMPFAIL => "temporary failure",
183 EX_PROTOCOL => "remote error in protocol",
184 EX_NOPERM => "permission denied",
185 EX_CONFIG => "configuration error",
186 }
187 }
188}
189
190impl core::fmt::Display for SysexitsError {
191 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
192 write!(f, "{}", self.as_str())
193 }
194}
195
196impl core::str::FromStr for SysexitsError {
197 type Err = ();
198
199 fn from_str(input: &str) -> Result<Self, Self::Err> {
200 use SysexitsError::*;
201 Ok(match input {
202 "EX_OK" => EX_OK,
203 "EX_USAGE" => EX_USAGE,
204 "EX_DATAERR" => EX_DATAERR,
205 "EX_NOINPUT" => EX_NOINPUT,
206 "EX_NOUSER" => EX_NOUSER,
207 "EX_NOHOST" => EX_NOHOST,
208 "EX_UNAVAILABLE" => EX_UNAVAILABLE,
209 "EX_SOFTWARE" => EX_SOFTWARE,
210 "EX_OSERR" => EX_OSERR,
211 "EX_OSFILE" => EX_OSFILE,
212 "EX_CANTCREAT" => EX_CANTCREAT,
213 "EX_IOERR" => EX_IOERR,
214 "EX_TEMPFAIL" => EX_TEMPFAIL,
215 "EX_PROTOCOL" => EX_PROTOCOL,
216 "EX_NOPERM" => EX_NOPERM,
217 "EX_CONFIG" => EX_CONFIG,
218 _ => match u8::from_str(input) {
219 Ok(code) => return Self::try_from(code).map_err(|_| ()),
220 Err(_) => return Err(()),
221 },
222 })
223 }
224}
225
226impl TryFrom<u8> for SysexitsError {
227 type Error = u8;
228
229 fn try_from(code: u8) -> Result<Self, Self::Error> {
230 use SysexitsError::*;
231 Ok(match code {
232 0 => EX_OK,
233 64 => EX_USAGE,
234 65 => EX_DATAERR,
235 66 => EX_NOINPUT,
236 67 => EX_NOUSER,
237 68 => EX_NOHOST,
238 69 => EX_UNAVAILABLE,
239 70 => EX_SOFTWARE,
240 71 => EX_OSERR,
241 72 => EX_OSFILE,
242 73 => EX_CANTCREAT,
243 74 => EX_IOERR,
244 75 => EX_TEMPFAIL,
245 76 => EX_PROTOCOL,
246 77 => EX_NOPERM,
247 78 => EX_CONFIG,
248 _ => return Err(code),
249 })
250 }
251}
252
253impl TryFrom<i32> for SysexitsError {
254 type Error = i32;
255
256 fn try_from(code: i32) -> Result<Self, Self::Error> {
257 Self::try_from(code as u8).map_err(|_| code)
258 }
259}
260
261#[cfg(feature = "std")]
262impl TryFrom<std::process::ExitStatus> for SysexitsError {
263 type Error = Option<i32>;
264
265 fn try_from(status: std::process::ExitStatus) -> Result<Self, Self::Error> {
266 match status.code() {
267 Some(code) => Self::try_from(code).map_err(|_| Some(code)),
268 None => Err(None),
269 }
270 }
271}
272
273#[cfg(feature = "std")]
274impl From<std::boxed::Box<dyn std::error::Error>> for SysexitsError {
275 fn from(error: std::boxed::Box<dyn std::error::Error>) -> Self {
276 Self::from(&error)
277 }
278}
279
280#[cfg(feature = "std")]
281impl From<&std::boxed::Box<dyn std::error::Error>> for SysexitsError {
282 fn from(_error: &std::boxed::Box<dyn std::error::Error>) -> Self {
283 Self::EX_SOFTWARE
284 }
285}
286
287#[cfg(feature = "std")]
288impl From<std::io::Error> for SysexitsError {
289 fn from(error: std::io::Error) -> Self {
290 Self::from(&error)
291 }
292}
293
294#[cfg(feature = "std")]
295impl From<&std::io::Error> for SysexitsError {
296 fn from(error: &std::io::Error) -> Self {
297 use std::io::ErrorKind::*;
298 match error.kind() {
299 AddrInUse => Self::EX_TEMPFAIL,
300 AddrNotAvailable => Self::EX_USAGE,
301 AlreadyExists => Self::EX_CANTCREAT,
302 BrokenPipe => Self::EX_IOERR,
303 ConnectionAborted => Self::EX_PROTOCOL,
304 ConnectionRefused => Self::EX_UNAVAILABLE,
305 ConnectionReset => Self::EX_PROTOCOL,
306 Interrupted => Self::EX_TEMPFAIL,
307 InvalidData => Self::EX_DATAERR,
308 InvalidInput => Self::EX_DATAERR,
309 NotConnected => Self::EX_PROTOCOL,
310 NotFound => Self::EX_NOINPUT,
311 Other => Self::EX_UNAVAILABLE,
312 OutOfMemory => Self::EX_TEMPFAIL,
313 PermissionDenied => Self::EX_NOPERM,
314 TimedOut => Self::EX_IOERR,
315 UnexpectedEof => Self::EX_IOERR,
316 Unsupported => Self::EX_SOFTWARE,
317 WouldBlock => Self::EX_IOERR,
318 WriteZero => Self::EX_IOERR,
319 _ => Self::EX_UNAVAILABLE, }
321 }
322}
323
324#[cfg(feature = "gofer")]
325impl From<gofer::Error> for SysexitsError {
326 fn from(error: gofer::Error) -> Self {
327 Self::from(&error)
328 }
329}
330
331#[cfg(feature = "gofer")]
332impl From<&gofer::Error> for SysexitsError {
333 fn from(error: &gofer::Error) -> Self {
334 use gofer::Error::*;
336 match error {
337 InvalidUrl(_) => Self::EX_DATAERR,
338 UnknownScheme(_) => Self::EX_DATAERR,
339 _ => Self::EX_SOFTWARE, }
341 }
342}
343
344#[cfg(feature = "serde-json")]
345impl From<serde_json::Error> for SysexitsError {
346 fn from(error: serde_json::Error) -> Self {
347 Self::from(&error)
348 }
349}
350
351#[cfg(feature = "serde-json")]
352impl From<&serde_json::Error> for SysexitsError {
353 fn from(error: &serde_json::Error) -> Self {
354 use serde_json::error::Category::*;
356 match error.classify() {
357 Io => Self::EX_IOERR,
358 Syntax => Self::EX_DATAERR,
359 Data => Self::EX_DATAERR,
360 Eof => Self::EX_NOINPUT,
361 _ => Self::EX_SOFTWARE, }
363 }
364}
365
366#[cfg(feature = "tokio")]
367impl From<tokio::task::JoinError> for SysexitsError {
368 fn from(error: tokio::task::JoinError) -> Self {
369 Self::from(&error)
370 }
371}
372
373#[cfg(feature = "tokio")]
374impl From<&tokio::task::JoinError> for SysexitsError {
375 fn from(_error: &tokio::task::JoinError) -> Self {
376 Self::EX_SOFTWARE
378 }
379}
380
381#[cfg(feature = "std")]
382impl std::process::Termination for SysexitsError {
383 fn report(self) -> std::process::ExitCode {
384 (self as u8).into()
385 }
386}
387
388#[cfg(feature = "std")]
389impl std::error::Error for SysexitsError {}
390
391#[cfg(feature = "error-stack")]
392impl error_stack::Context for SysexitsError {}
393
394#[cfg(feature = "std")]
396pub fn exit(code: SysexitsError) -> ! {
397 std::process::exit(code as i32);
398}
399
400#[cfg(feature = "std")]
403#[macro_export]
404macro_rules! abort {
405 ($code:expr, $($t:tt)*) => {{
406 std::eprintln!($($t)*);
407 exit($code)
408 }};
409}