1use crate::error::Inner::{Custom, Simple};
2use std::fmt::{Debug, Display, Formatter};
3
4pub type Result<T> = std::result::Result<T, Error>;
6
7type AnyError = Box<dyn std::error::Error + Sync + Send>;
8
9pub struct Error {
11 inner: Inner,
12}
13
14enum Inner {
15 Simple(ErrorKind),
16 Custom(CustomError),
17}
18
19impl Error {
20 pub fn new<E: Into<AnyError>>(kind: ErrorKind, error: E) -> Self {
30 Error {
31 inner: Custom(
32 CustomError::new(
33 kind,
34 error.into(),
35 None
36 )
37 ),
38 }
39 }
40
41 pub fn kind(&self) -> &ErrorKind {
43 match &self.inner {
44 Inner::Simple(kind) => kind,
45 Inner::Custom(custom) => &custom.kind,
46 }
47 }
48
49 pub fn with_message<S: Into<AnyError>>(&self, msg: S) -> Self {
60 match &self.inner {
61 Simple(kind) => {
62 Error::new(kind.clone(), msg.into())
63 }
64 Custom(custom) => {
65 Error {
66 inner: Custom(CustomError::new(
67 custom.kind.clone(),
68 custom.error.to_string().into(),
69 Some(msg.into().to_string())
70 ))
71 }
72 }
73 }
74 }
75
76 pub fn exit(self) -> ! {
78 if matches!(self.kind(), ErrorKind::DisplayHelp(_) | ErrorKind::DisplayVersion(_)) {
79 println!("{}", self);
80 } else {
81 eprintln!("Error: {}", self);
83 }
84
85 std::process::exit(0)
86 }
87}
88
89impl std::error::Error for Error {
90 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
91 match self.inner {
92 Simple(_) => None,
93 Custom(ref custom) => Some(custom.error.as_ref()),
94 }
95 }
96}
97
98impl Display for Error {
99 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
100 match &self.inner {
101 Inner::Simple(kind) => Display::fmt(kind, f),
102 Inner::Custom(custom) => Display::fmt(custom, f)
103 }
104 }
105}
106
107impl Debug for Error {
108 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
109 Display::fmt(self, f)
110 }
111}
112
113impl From<ErrorKind> for Error {
114 fn from(kind: ErrorKind) -> Self {
115 Error {
116 inner: Simple(kind),
117 }
118 }
119}
120
121#[derive(Clone, Eq, PartialEq)]
123pub enum ErrorKind {
124 InvalidArgument(String),
126 InvalidArgumentCount,
128 InvalidExpression,
130 UnexpectedOption(String),
132 UnexpectedCommand(String),
134 MissingOption(String),
136 Other,
138
139 DisplayHelp(String),
143
144 DisplayVersion(String),
148
149 #[doc(hidden)]
151 FallthroughHelp
152}
153
154impl Display for ErrorKind {
155 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
156 match self {
157 ErrorKind::InvalidArgument(s) => write!(f, "invalid value for argument '{}'", s),
158 ErrorKind::InvalidArgumentCount => write!(f, "invalid argument count"),
159 ErrorKind::InvalidExpression => write!(f, "invalid expression"),
160 ErrorKind::UnexpectedOption(s) => write!(f, "unexpected option: '{}'", s),
161 ErrorKind::UnexpectedCommand(s) => write!(f, "unexpected command: '{}'", s),
162 ErrorKind::MissingOption(s) => write!(f, "'{}' is required", s),
163 ErrorKind::Other => write!(f, "unexpected error"),
164 ErrorKind::DisplayHelp(s) => write!(f, "{}", s),
165 ErrorKind::DisplayVersion(s) => write!(f, "{}", s),
166 ErrorKind::FallthroughHelp => panic!("`ErrorKind::FallthroughHelp` should not be used as an error")
167 }
168 }
169}
170
171impl Debug for ErrorKind {
172 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
173 Display::fmt(self, f)
174 }
175}
176
177struct CustomError {
178 kind: ErrorKind,
179 error: AnyError,
180 info: Option<String>
181}
182
183impl CustomError {
184 pub fn new(kind: ErrorKind, error: AnyError, info: Option<String>) -> Self {
185 CustomError {
186 kind,
187 error,
188 info
189 }
190 }
191}
192
193impl Display for CustomError {
194 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
195 if let Some(info) = &self.info {
196 write!(f, "{}: {}\n{}", self.kind, self.error, info)
197 } else {
198 write!(f, "{}: {}", self.kind, self.error)
199 }
200 }
201}