1use self::KindPriv::*;
2
3use std::error;
4use std::fmt;
5use http::StatusCode;
6
7#[derive(Debug)]
9pub struct Builder {
10 kind: Option<(String, String)>,
11 detail: Option<String>,
12 status: Option<StatusCode>,
13}
14
15#[derive(Serialize)]
18pub struct Error {
19 #[serde(rename = "type")]
20 kind: String,
21 title: String,
22 #[serde(skip_serializing_if = "Option::is_none")]
25 detail: Option<String>,
26 #[serde(skip)]
27 status: StatusCode,
28
29 #[serde(skip)]
31 error_kind: ErrorKind,
32}
33
34impl Builder {
37 fn new() -> Self {
38 Self {
39 kind: None,
40 detail: None,
41 status: None,
42 }
43 }
44
45 pub fn status(self, status: StatusCode) -> Self {
47 Self {
48 kind: self.kind,
49 detail: self.detail,
50 status: Some(status),
51
52 }
53 }
54
55 pub fn kind(self, kind: &str, title: &str) -> Self {
57 Self {
58 kind: Some((kind.to_owned(), title.to_owned())),
59 detail: self.detail,
60 status: self.status,
61 }
62 }
63
64 pub fn detail(self, detail: &str) -> Self {
66 Self {
67 kind: self.kind,
68 detail: Some(detail.to_owned()),
69 status: self.status,
70 }
71 }
72
73 pub fn build(self) -> Error {
75 let mut err =
76 match (self.kind, self.status) {
77 (Some((ref kind, ref title)), Some(status)) => Error::new(kind, title, status),
78 (Some(_), None) => Error::from(StatusCode::INTERNAL_SERVER_ERROR),
79 (None, Some(status)) => Error::from(status),
80 (None, None) => Error::from(StatusCode::INTERNAL_SERVER_ERROR),
81 };
82
83 match self.detail {
84 Some(ref detail) => {
85 err.set_detail(detail);
86 err
87 },
88 None => err,
89 }
90 }
91}
92
93impl Error {
96 #[deprecated(note="return value of the function will be changed to &str")]
100 pub fn kind(&self) -> &ErrorKind {
101 &self.error_kind
102 }
103
104 pub fn new(kind: &str, title: &str, status: StatusCode) -> Self {
106 Self {
107 kind: kind.to_owned(),
108 title: title.to_owned(),
109 detail: None,
110 status,
111
112 error_kind: ErrorKind::new(&status),
114 }
115 }
116
117 pub fn set_detail(&mut self, value: &str) -> &mut Self {
119 self.detail = Some(value.to_owned());
120 self
121 }
122
123 pub fn status_code(&self) -> StatusCode {
125 self.status
126 }
127
128 pub fn builder() -> Builder {
130 Builder::new()
131 }
132}
133
134impl error::Error for Error {
135 fn description(&self) -> &str {
136 self.status_code().canonical_reason().unwrap_or("Unknown status code")
137 }
138}
139
140impl fmt::Debug for Error {
141 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
142 fmt.debug_struct("Error")
143 .field("kind", &self.kind)
144 .field("title", &self.title)
145 .field("detail", &self.detail)
146 .field("status", &self.status)
147 .finish()
148 }
149}
150
151impl fmt::Display for Error {
152 #[allow(deprecated)] fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
154 write!(
155 fmt,
156 "[{}] {}",
157 self.kind, self.title,
158 )?;
159
160 if let Some(ref detail) = self.detail {
161 write!(fmt, ": {}", detail)?;
162 }
163
164 use std::error::Error;
165 if let Some(ref cause) = self.cause() {
166 write!(fmt, ": {}", cause)?;
167 }
168
169 Ok(())
170 }
171}
172
173impl From<StatusCode> for Error {
174 fn from(status: StatusCode) -> Self {
175 let title = status.canonical_reason().unwrap_or("Unknown status code");
176 Self {
177 kind: String::from("about:blank"),
178 title: title.to_owned(),
179 detail: None,
180 status,
181
182 error_kind: ErrorKind::new(&status),
184 }
185 }
186}
187
188pub struct ErrorKind {
192 kind: KindPriv,
193}
194
195#[derive(Debug, Eq, PartialEq, Clone, Copy)]
196enum KindPriv {
197 BadRequest,
198 Unauthorized,
199 Fordidden,
200 NotFound,
201 UnprocessableEntity,
202 Internal,
203}
204
205impl From<ErrorKind> for Error {
206 fn from(error_kind: ErrorKind) -> Error {
207 error_kind.status_code().into()
208 }
209}
210
211impl ErrorKind {
214 #[deprecated(note="please use 'Error::from(http::StatusCode::BAD_REQUEST)' instead")]
216 pub fn bad_request() -> ErrorKind {
217 ErrorKind { kind: BadRequest }
218 }
219
220 #[deprecated(note="please use 'kind() == http::StatusCode::BAD_REQUEST' instead")]
222 pub fn is_bad_request(&self) -> bool {
223 self.kind == BadRequest
224 }
225
226 #[deprecated(note="please use 'Error::from(http::StatusCode::UNAUTHORIZED)' instead")]
228 pub fn unauthorized() -> ErrorKind {
229 ErrorKind { kind: Unauthorized }
230 }
231
232 #[deprecated(note="please use 'Error::from(http::StatusCode::FORBIDDEN)' instead")]
234 pub fn forbidden() -> ErrorKind {
235 ErrorKind { kind: Fordidden }
236 }
237
238 #[deprecated(note="please use 'Error::from(http::StatusCode::NOT_FOUND)' instead")]
240 pub fn not_found() -> ErrorKind {
241 ErrorKind { kind: NotFound }
242 }
243
244 #[deprecated(note="please use 'kind() == http::StatusCode::NOT_FOUND' instead")]
246 pub fn is_not_found(&self) -> bool {
247 self.kind == NotFound
248 }
249
250 #[deprecated(note="please use 'Error::from(http::StatusCode::UNPROCESSABLE_ENTITY)' instead")]
252 pub fn unprocessable_entity() -> ErrorKind {
253 ErrorKind { kind: UnprocessableEntity }
254 }
255
256 #[deprecated(note="please use 'Error::from(http::StatusCode::INTERNAL_SERVER_ERROR)' instead")]
259 pub fn internal() -> ErrorKind {
260 ErrorKind { kind: Internal }
261 }
262
263 #[deprecated(note="please use 'kind() == http::StatusCode::INTERNAL_SERVER_ERROR' instead")]
265 pub fn is_internal(&self) -> bool {
266 self.kind == Internal
267 }
268
269 fn status_code(&self) -> StatusCode {
270 match self.kind {
271 BadRequest => StatusCode::BAD_REQUEST,
272 Unauthorized => StatusCode::UNAUTHORIZED,
273 Fordidden => StatusCode::FORBIDDEN,
274 NotFound => StatusCode::NOT_FOUND,
275 UnprocessableEntity => StatusCode::UNPROCESSABLE_ENTITY,
276 Internal => StatusCode::INTERNAL_SERVER_ERROR,
277 }
278 }
279
280 fn new(status: &StatusCode) -> Self {
281 match status {
282 &StatusCode::BAD_REQUEST => ErrorKind {
283 kind: BadRequest
284 },
285 &StatusCode::UNAUTHORIZED => ErrorKind {
286 kind: Unauthorized
287 },
288 &StatusCode::FORBIDDEN => ErrorKind {
289 kind: Fordidden
290 },
291 &StatusCode::NOT_FOUND => ErrorKind {
292 kind: NotFound
293 },
294 &StatusCode::UNPROCESSABLE_ENTITY => ErrorKind {
295 kind: UnprocessableEntity
296 },
297 _ => ErrorKind {
298 kind: Internal
299 },
300 }
301 }
302}
303
304impl fmt::Debug for ErrorKind {
305 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
306 match self.kind {
307 BadRequest => "ErrorKind::BadRequest",
308 Unauthorized => "ErrorKind::Unauthorized",
309 Fordidden => "ErrorKind::Forbidden",
310 NotFound => "ErrorKind::NotFound",
311 UnprocessableEntity => "ErrorKind::UnprocessableEntity",
312 Internal => "ErrorKind::Internal",
313 }.fmt(fmt)
314 }
315}