1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! # thistermination
//!
//! thistermination is a library crate inspired by [thiserror](https://crates.io/crates/thiserror) to add the [`std::process::Termination`](https://doc.rust-lang.org/std/process/trait.Termination.html) trait to error enums.
//!
//! ## Usage
//!
//! To add the `std::process::Termination` trait to an enum, you can use one of three possible derive macros:
//!
//! - `#[derive(Termination)]`: is intended to be used in combination with thiserror, this macro implements the traits `std::process::Termination` and `std::fmt::Debug`. The `exit_code` defaults to `libc::EXIT_FAILURE`, and the Debug message is the same as the Display message unless explicitly set using `exit_code` and `msg`.
//! ```rust
//! use thistermination::{Termination};
//! use thiserror::Error;
//!
//! #[derive(Error, Termination)]
//! pub enum RequestError {
//! #[error("request failed {0:?}")]
//! RequestFailed(#[from] reqwest::Error),
//! #[termination(msg("exiting wrong api key"))]
//! #[error("wrong api key")]
//! WrongAPIKey,
//! #[termination(exit_code(3))]
//! #[error("failed with status {0}")]
//! RequestStatusError(u16),
//! #[termination(exit_code(4), msg("exiting failed to load image {error:?}"))]
//! #[error("failed to load image {error:?}")]
//! ImageLoadError{#[from] error: image::ImageError},
//! }
//!
//! fn main() -> Result<(), RequestError> {
//! Err(RequestError::WrongAPIKey)
//! }
//! ```
//!
//! - `#[derive(TerminationFull)]`: is intended to be used without thiserror, this macro implements the traits `std::process::Termination`, `std::fmt::Debug`, `std::fmt::Display`, and `std::error::Error`. The `exit_code` defaults to `libc::EXIT_FAILURE`, and `msg` is required and used for both Display and Debug.
//! ```rust
//! use thistermination::{TerminationFull};
//!
//! #[derive(TerminationFull)]
//! pub enum RequestError {
//! #[termination(exit_code(1), msg("request failed {0:?}"))]
//! RequestFailed(#[from] reqwest::Error),
//! #[termination(exit_code(2), msg("wrong api key"))]
//! WrongAPIKey,
//! #[termination(exit_code(3), msg("failed with status {0}"))]
//! RequestStatusError(u16),
//! #[termination(exit_code(4), msg("failed to load image {error:?}"))]
//! ImageLoadError{#[from] error: image::ImageError},
//! }
//!
//! fn main() -> Result<(), RequestError> {
//! Err(RequestError::WrongAPIKey)
//! }
//! ```
//!
//! - `#[derive(TerminationNoDebug)]`: is the most basic variant, implementing only the `std::process::Termination` trait. If no `exit_code` is provided, it defaults to `libc::EXIT_FAILURE`. However, the `std::fmt::Debug` trait is necessary for the enum to be returned by the `main` function and must be implemented manually or using the Debug macro.
//! ```rust
//! use thistermination::{TerminationNoDebug};
//!
//! #[derive(TerminationNoDebug, Debug)]
//! pub enum RequestError {
//! #[termination(exit_code(1))]
//! RequestFailed(reqwest::Error),
//! WrongAPIKey,
//! #[termination(exit_code(3))]
//! RequestStatusError(u16),
//! ImageLoadError{error: image::ImageError},
//! }
//!
//! fn main() -> Result<(), RequestError> {
//! Err(RequestError::WrongAPIKey)
//! }
//! ```
//!
//! ## Details
//!
//! - thistermination does not appear in your public API; the macros simply implement the the various traits.
//!
//! - The macros can be derived for unit enums, enums with named fields, and enum tuples.
//!
//! - `msg` supports accessing the fields of the enum in a format string manner
//!
//! - `#[termination(msg("{var}"))]` ⟶ `write!("{}", self.var)`
//! - `#[termination(msg("{0}"))]` ⟶ `write!("{}", self.0)`
//! - `#[termination(msg("{var:?}"))]` ⟶ `write!("{:?}", self.var)`
//! - `#[termination(msg("{0:?}"))]` ⟶ `write!("{:?}", self.0)`
//!
//! You can also specify additional format string arguments for `msg`
//! ```rust
//! # use thistermination::{TerminationFull};
//! #[derive(TerminationFull)]
//! pub enum RequestError {
//! #[termination(exit_code(4), msg("failed to load image {0:?}"))]
//! ImageLoadError(#[from] image::ImageError),
//! }
//! ```
//!
//! - Using `#[from]` will generate a `std::convert::From` implementation for the specific variant. A variant with `#[from]` is not allowed to contain any additional fields and can only be used in combination with `#[derive(TerminationFull)]`.
//!
//! ```rust
//! # use thistermination::{TerminationFull};
//! #[derive(TerminationFull)]
//! pub enum CLIError {
//! #[termination(exit_code(4), msg("Invalid argument {0}, expected < {}", i16::MAX))]
//! InvalidArgument(u16),
//! }
//! # fn main() -> Result<(), CLIError> {
//! # Err(CLIError::InvalidArgument(5))
//! # }
//! ```
//!
//! - You can also change the default values of `exit_code` and `msg` by adding the `#[termination(...)]` helper attribute to the enum itself.
//!
//! ```rust
//! # use thistermination::{Termination};
//! # use thiserror::Error;
//! #[derive(Error, Termination)]
//! #[termination(exit_code(3), msg("Fatal Error"))]
//! pub enum RequestError {
//! #[error("request failed {0:?}")]
//! RequestFailed(#[from] reqwest::Error),
//! #[error("wrong api key")]
//! WrongAPIKey,
//! #[error("failed with status {0}")]
//! RequestStatusError(u16),
//! #[termination(exit_code(4), msg("exiting failed to load image {error:?}"))]
//! #[error("failed to load image {error:?}")]
//! ImageLoadError{#[from] error: image::ImageError},
//! }
//! # fn main() -> Result<(), RequestError> {
//! # Err(RequestError::WrongAPIKey)
//! # }
//! ```
use TokenStream;
use _derive_termination;
use _derive_termination_full;
use _derive_termination_no_debug;