]>
Commit | Line | Data |
---|---|---|
c34b1796 AL |
1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! Traits for working with Errors. | |
12 | //! | |
13 | //! # The `Error` trait | |
14 | //! | |
15 | //! `Error` is a trait representing the basic expectations for error values, | |
c30ab7b3 | 16 | //! i.e. values of type `E` in [`Result<T, E>`]. At a minimum, errors must provide |
c34b1796 | 17 | //! a description, but they may optionally provide additional detail (via |
c30ab7b3 | 18 | //! [`Display`]) and cause chain information: |
c34b1796 AL |
19 | //! |
20 | //! ``` | |
21 | //! use std::fmt::Display; | |
22 | //! | |
23 | //! trait Error: Display { | |
24 | //! fn description(&self) -> &str; | |
25 | //! | |
26 | //! fn cause(&self) -> Option<&Error> { None } | |
27 | //! } | |
28 | //! ``` | |
29 | //! | |
c30ab7b3 | 30 | //! The [`cause`] method is generally used when errors cross "abstraction |
c34b1796 AL |
31 | //! boundaries", i.e. when a one module must report an error that is "caused" |
32 | //! by an error from a lower-level module. This setup makes it possible for the | |
33 | //! high-level module to provide its own errors that do not commit to any | |
34 | //! particular implementation, but also reveal some of its implementation for | |
c30ab7b3 SL |
35 | //! debugging via [`cause`] chains. |
36 | //! | |
37 | //! [`Result<T, E>`]: ../result/enum.Result.html | |
38 | //! [`Display`]: ../fmt/trait.Display.html | |
39 | //! [`cause`]: trait.Error.html#method.cause | |
c34b1796 AL |
40 | |
41 | #![stable(feature = "rust1", since = "1.0.0")] | |
42 | ||
43 | // A note about crates and the facade: | |
44 | // | |
45 | // Originally, the `Error` trait was defined in libcore, and the impls | |
46 | // were scattered about. However, coherence objected to this | |
47 | // arrangement, because to create the blanket impls for `Box` required | |
48 | // knowing that `&str: !Error`, and we have no means to deal with that | |
49 | // sort of conflict just now. Therefore, for the time being, we have | |
50 | // moved the `Error` trait into libstd. As we evolve a sol'n to the | |
51 | // coherence challenge (e.g., specialization, neg impls, etc) we can | |
52 | // reconsider what crate these items belong in. | |
53 | ||
bd371182 | 54 | use any::TypeId; |
5bcae85e | 55 | use cell; |
54a0048b | 56 | use char; |
c34b1796 | 57 | use fmt::{self, Debug, Display}; |
bd371182 | 58 | use mem::transmute; |
c34b1796 | 59 | use num; |
c34b1796 | 60 | use str; |
9e0c209e | 61 | use string; |
c34b1796 AL |
62 | |
63 | /// Base functionality for all errors in Rust. | |
64 | #[stable(feature = "rust1", since = "1.0.0")] | |
9e0c209e | 65 | pub trait Error: Debug + Display { |
c34b1796 AL |
66 | /// A short description of the error. |
67 | /// | |
c30ab7b3 SL |
68 | /// The description should only be used for a simple message. |
69 | /// It should not contain newlines or sentence-ending punctuation, | |
70 | /// to facilitate embedding in larger user-facing strings. | |
71 | /// For showing formatted error messages with more information see | |
72 | /// [`Display`]. | |
73 | /// | |
74 | /// [`Display`]: ../fmt/trait.Display.html | |
5bcae85e SL |
75 | /// |
76 | /// # Examples | |
77 | /// | |
78 | /// ``` | |
79 | /// use std::error::Error; | |
80 | /// | |
81 | /// match "xc".parse::<u32>() { | |
82 | /// Err(e) => { | |
83 | /// println!("Error: {}", e.description()); | |
84 | /// } | |
85 | /// _ => println!("No error"), | |
86 | /// } | |
87 | /// ``` | |
c34b1796 AL |
88 | #[stable(feature = "rust1", since = "1.0.0")] |
89 | fn description(&self) -> &str; | |
90 | ||
91 | /// The lower-level cause of this error, if any. | |
5bcae85e SL |
92 | /// |
93 | /// # Examples | |
94 | /// | |
95 | /// ``` | |
96 | /// use std::error::Error; | |
97 | /// use std::fmt; | |
98 | /// | |
99 | /// #[derive(Debug)] | |
100 | /// struct SuperError { | |
101 | /// side: SuperErrorSideKick, | |
102 | /// } | |
103 | /// | |
104 | /// impl fmt::Display for SuperError { | |
105 | /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
106 | /// write!(f, "SuperError is here!") | |
107 | /// } | |
108 | /// } | |
109 | /// | |
110 | /// impl Error for SuperError { | |
111 | /// fn description(&self) -> &str { | |
476ff2be | 112 | /// "I'm the superhero of errors" |
5bcae85e SL |
113 | /// } |
114 | /// | |
115 | /// fn cause(&self) -> Option<&Error> { | |
116 | /// Some(&self.side) | |
117 | /// } | |
118 | /// } | |
119 | /// | |
120 | /// #[derive(Debug)] | |
121 | /// struct SuperErrorSideKick; | |
122 | /// | |
123 | /// impl fmt::Display for SuperErrorSideKick { | |
124 | /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
125 | /// write!(f, "SuperErrorSideKick is here!") | |
126 | /// } | |
127 | /// } | |
128 | /// | |
129 | /// impl Error for SuperErrorSideKick { | |
130 | /// fn description(&self) -> &str { | |
476ff2be | 131 | /// "I'm SuperError side kick" |
5bcae85e SL |
132 | /// } |
133 | /// } | |
134 | /// | |
135 | /// fn get_super_error() -> Result<(), SuperError> { | |
136 | /// Err(SuperError { side: SuperErrorSideKick }) | |
137 | /// } | |
138 | /// | |
139 | /// fn main() { | |
140 | /// match get_super_error() { | |
141 | /// Err(e) => { | |
142 | /// println!("Error: {}", e.description()); | |
143 | /// println!("Caused by: {}", e.cause().unwrap()); | |
144 | /// } | |
145 | /// _ => println!("No error"), | |
146 | /// } | |
147 | /// } | |
148 | /// ``` | |
c34b1796 AL |
149 | #[stable(feature = "rust1", since = "1.0.0")] |
150 | fn cause(&self) -> Option<&Error> { None } | |
bd371182 AL |
151 | |
152 | /// Get the `TypeId` of `self` | |
153 | #[doc(hidden)] | |
62682a34 | 154 | #[unstable(feature = "error_type_id", |
e9174d1e SL |
155 | reason = "unclear whether to commit to this public implementation detail", |
156 | issue = "27745")] | |
bd371182 AL |
157 | fn type_id(&self) -> TypeId where Self: 'static { |
158 | TypeId::of::<Self>() | |
159 | } | |
c34b1796 AL |
160 | } |
161 | ||
162 | #[stable(feature = "rust1", since = "1.0.0")] | |
163 | impl<'a, E: Error + 'a> From<E> for Box<Error + 'a> { | |
164 | fn from(err: E) -> Box<Error + 'a> { | |
165 | Box::new(err) | |
166 | } | |
167 | } | |
168 | ||
169 | #[stable(feature = "rust1", since = "1.0.0")] | |
9346a6ac AL |
170 | impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<Error + Send + Sync + 'a> { |
171 | fn from(err: E) -> Box<Error + Send + Sync + 'a> { | |
c34b1796 AL |
172 | Box::new(err) |
173 | } | |
174 | } | |
175 | ||
176 | #[stable(feature = "rust1", since = "1.0.0")] | |
9346a6ac AL |
177 | impl From<String> for Box<Error + Send + Sync> { |
178 | fn from(err: String) -> Box<Error + Send + Sync> { | |
c34b1796 AL |
179 | #[derive(Debug)] |
180 | struct StringError(String); | |
181 | ||
182 | impl Error for StringError { | |
183 | fn description(&self) -> &str { &self.0 } | |
184 | } | |
185 | ||
186 | impl Display for StringError { | |
187 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
188 | Display::fmt(&self.0, f) | |
189 | } | |
190 | } | |
191 | ||
9346a6ac AL |
192 | Box::new(StringError(err)) |
193 | } | |
194 | } | |
195 | ||
7cac9316 | 196 | #[stable(feature = "string_box_error", since = "1.6.0")] |
92a42be0 SL |
197 | impl From<String> for Box<Error> { |
198 | fn from(str_err: String) -> Box<Error> { | |
199 | let err1: Box<Error + Send + Sync> = From::from(str_err); | |
200 | let err2: Box<Error> = err1; | |
201 | err2 | |
202 | } | |
203 | } | |
204 | ||
9346a6ac AL |
205 | #[stable(feature = "rust1", since = "1.0.0")] |
206 | impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> { | |
207 | fn from(err: &'b str) -> Box<Error + Send + Sync + 'a> { | |
62682a34 | 208 | From::from(String::from(err)) |
c34b1796 AL |
209 | } |
210 | } | |
211 | ||
7cac9316 | 212 | #[stable(feature = "string_box_error", since = "1.6.0")] |
92a42be0 SL |
213 | impl<'a> From<&'a str> for Box<Error> { |
214 | fn from(err: &'a str) -> Box<Error> { | |
215 | From::from(String::from(err)) | |
216 | } | |
217 | } | |
218 | ||
cc61c64b XL |
219 | #[unstable(feature = "never_type_impls", issue = "35121")] |
220 | impl Error for ! { | |
221 | fn description(&self) -> &str { *self } | |
222 | } | |
223 | ||
c34b1796 AL |
224 | #[stable(feature = "rust1", since = "1.0.0")] |
225 | impl Error for str::ParseBoolError { | |
226 | fn description(&self) -> &str { "failed to parse bool" } | |
227 | } | |
228 | ||
229 | #[stable(feature = "rust1", since = "1.0.0")] | |
230 | impl Error for str::Utf8Error { | |
231 | fn description(&self) -> &str { | |
9346a6ac | 232 | "invalid utf-8: corrupt contents" |
c34b1796 AL |
233 | } |
234 | } | |
235 | ||
236 | #[stable(feature = "rust1", since = "1.0.0")] | |
237 | impl Error for num::ParseIntError { | |
238 | fn description(&self) -> &str { | |
62682a34 | 239 | self.__description() |
c34b1796 AL |
240 | } |
241 | } | |
242 | ||
a7813a04 XL |
243 | #[unstable(feature = "try_from", issue = "33417")] |
244 | impl Error for num::TryFromIntError { | |
245 | fn description(&self) -> &str { | |
246 | self.__description() | |
247 | } | |
248 | } | |
249 | ||
c34b1796 AL |
250 | #[stable(feature = "rust1", since = "1.0.0")] |
251 | impl Error for num::ParseFloatError { | |
252 | fn description(&self) -> &str { | |
d9579d0f | 253 | self.__description() |
c34b1796 AL |
254 | } |
255 | } | |
256 | ||
257 | #[stable(feature = "rust1", since = "1.0.0")] | |
258 | impl Error for string::FromUtf8Error { | |
259 | fn description(&self) -> &str { | |
260 | "invalid utf-8" | |
261 | } | |
262 | } | |
263 | ||
264 | #[stable(feature = "rust1", since = "1.0.0")] | |
265 | impl Error for string::FromUtf16Error { | |
266 | fn description(&self) -> &str { | |
267 | "invalid utf-16" | |
268 | } | |
269 | } | |
270 | ||
7453a54e SL |
271 | #[stable(feature = "str_parse_error2", since = "1.8.0")] |
272 | impl Error for string::ParseError { | |
273 | fn description(&self) -> &str { | |
274 | match *self {} | |
275 | } | |
276 | } | |
277 | ||
54a0048b SL |
278 | #[stable(feature = "decode_utf16", since = "1.9.0")] |
279 | impl Error for char::DecodeUtf16Error { | |
280 | fn description(&self) -> &str { | |
281 | "unpaired surrogate found" | |
282 | } | |
283 | } | |
284 | ||
7cac9316 | 285 | #[stable(feature = "box_error", since = "1.8.0")] |
7453a54e SL |
286 | impl<T: Error> Error for Box<T> { |
287 | fn description(&self) -> &str { | |
288 | Error::description(&**self) | |
289 | } | |
290 | ||
291 | fn cause(&self) -> Option<&Error> { | |
292 | Error::cause(&**self) | |
293 | } | |
294 | } | |
295 | ||
3157f602 XL |
296 | #[stable(feature = "fmt_error", since = "1.11.0")] |
297 | impl Error for fmt::Error { | |
298 | fn description(&self) -> &str { | |
299 | "an error occurred when formatting an argument" | |
300 | } | |
301 | } | |
302 | ||
9e0c209e SL |
303 | #[stable(feature = "try_borrow", since = "1.13.0")] |
304 | impl Error for cell::BorrowError { | |
5bcae85e SL |
305 | fn description(&self) -> &str { |
306 | "already mutably borrowed" | |
307 | } | |
308 | } | |
309 | ||
9e0c209e SL |
310 | #[stable(feature = "try_borrow", since = "1.13.0")] |
311 | impl Error for cell::BorrowMutError { | |
5bcae85e SL |
312 | fn description(&self) -> &str { |
313 | "already borrowed" | |
314 | } | |
315 | } | |
316 | ||
9e0c209e SL |
317 | #[unstable(feature = "try_from", issue = "33417")] |
318 | impl Error for char::CharTryFromError { | |
319 | fn description(&self) -> &str { | |
320 | "converted integer out of range for `char`" | |
321 | } | |
322 | } | |
323 | ||
bd371182 AL |
324 | // copied from any.rs |
325 | impl Error + 'static { | |
326 | /// Returns true if the boxed type is the same as `T` | |
c1a9b12d | 327 | #[stable(feature = "error_downcast", since = "1.3.0")] |
bd371182 AL |
328 | #[inline] |
329 | pub fn is<T: Error + 'static>(&self) -> bool { | |
330 | // Get TypeId of the type this function is instantiated with | |
331 | let t = TypeId::of::<T>(); | |
332 | ||
333 | // Get TypeId of the type in the trait object | |
334 | let boxed = self.type_id(); | |
335 | ||
336 | // Compare both TypeIds on equality | |
337 | t == boxed | |
338 | } | |
339 | ||
340 | /// Returns some reference to the boxed value if it is of type `T`, or | |
341 | /// `None` if it isn't. | |
c1a9b12d | 342 | #[stable(feature = "error_downcast", since = "1.3.0")] |
bd371182 AL |
343 | #[inline] |
344 | pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> { | |
345 | if self.is::<T>() { | |
346 | unsafe { | |
9e0c209e | 347 | Some(&*(self as *const Error as *const T)) |
bd371182 AL |
348 | } |
349 | } else { | |
350 | None | |
351 | } | |
352 | } | |
353 | ||
354 | /// Returns some mutable reference to the boxed value if it is of type `T`, or | |
355 | /// `None` if it isn't. | |
c1a9b12d | 356 | #[stable(feature = "error_downcast", since = "1.3.0")] |
bd371182 AL |
357 | #[inline] |
358 | pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { | |
359 | if self.is::<T>() { | |
360 | unsafe { | |
9e0c209e | 361 | Some(&mut *(self as *mut Error as *mut T)) |
bd371182 AL |
362 | } |
363 | } else { | |
364 | None | |
365 | } | |
366 | } | |
367 | } | |
368 | ||
369 | impl Error + 'static + Send { | |
370 | /// Forwards to the method defined on the type `Any`. | |
c1a9b12d | 371 | #[stable(feature = "error_downcast", since = "1.3.0")] |
bd371182 AL |
372 | #[inline] |
373 | pub fn is<T: Error + 'static>(&self) -> bool { | |
374 | <Error + 'static>::is::<T>(self) | |
375 | } | |
376 | ||
377 | /// Forwards to the method defined on the type `Any`. | |
c1a9b12d | 378 | #[stable(feature = "error_downcast", since = "1.3.0")] |
bd371182 AL |
379 | #[inline] |
380 | pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> { | |
381 | <Error + 'static>::downcast_ref::<T>(self) | |
382 | } | |
383 | ||
384 | /// Forwards to the method defined on the type `Any`. | |
c1a9b12d SL |
385 | #[stable(feature = "error_downcast", since = "1.3.0")] |
386 | #[inline] | |
387 | pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { | |
388 | <Error + 'static>::downcast_mut::<T>(self) | |
389 | } | |
390 | } | |
391 | ||
392 | impl Error + 'static + Send + Sync { | |
393 | /// Forwards to the method defined on the type `Any`. | |
394 | #[stable(feature = "error_downcast", since = "1.3.0")] | |
395 | #[inline] | |
396 | pub fn is<T: Error + 'static>(&self) -> bool { | |
397 | <Error + 'static>::is::<T>(self) | |
398 | } | |
399 | ||
400 | /// Forwards to the method defined on the type `Any`. | |
401 | #[stable(feature = "error_downcast", since = "1.3.0")] | |
402 | #[inline] | |
403 | pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> { | |
404 | <Error + 'static>::downcast_ref::<T>(self) | |
405 | } | |
406 | ||
407 | /// Forwards to the method defined on the type `Any`. | |
408 | #[stable(feature = "error_downcast", since = "1.3.0")] | |
bd371182 AL |
409 | #[inline] |
410 | pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> { | |
411 | <Error + 'static>::downcast_mut::<T>(self) | |
412 | } | |
413 | } | |
414 | ||
415 | impl Error { | |
416 | #[inline] | |
c1a9b12d | 417 | #[stable(feature = "error_downcast", since = "1.3.0")] |
bd371182 AL |
418 | /// Attempt to downcast the box to a concrete type. |
419 | pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Error>> { | |
420 | if self.is::<T>() { | |
421 | unsafe { | |
9e0c209e SL |
422 | let raw: *mut Error = Box::into_raw(self); |
423 | Ok(Box::from_raw(raw as *mut T)) | |
bd371182 AL |
424 | } |
425 | } else { | |
426 | Err(self) | |
427 | } | |
428 | } | |
429 | } | |
430 | ||
431 | impl Error + Send { | |
432 | #[inline] | |
c1a9b12d | 433 | #[stable(feature = "error_downcast", since = "1.3.0")] |
bd371182 | 434 | /// Attempt to downcast the box to a concrete type. |
c1a9b12d SL |
435 | pub fn downcast<T: Error + 'static>(self: Box<Self>) |
436 | -> Result<Box<T>, Box<Error + Send>> { | |
bd371182 AL |
437 | let err: Box<Error> = self; |
438 | <Error>::downcast(err).map_err(|s| unsafe { | |
439 | // reapply the Send marker | |
440 | transmute::<Box<Error>, Box<Error + Send>>(s) | |
441 | }) | |
442 | } | |
443 | } | |
c1a9b12d SL |
444 | |
445 | impl Error + Send + Sync { | |
446 | #[inline] | |
447 | #[stable(feature = "error_downcast", since = "1.3.0")] | |
448 | /// Attempt to downcast the box to a concrete type. | |
449 | pub fn downcast<T: Error + 'static>(self: Box<Self>) | |
450 | -> Result<Box<T>, Box<Self>> { | |
451 | let err: Box<Error> = self; | |
452 | <Error>::downcast(err).map_err(|s| unsafe { | |
453 | // reapply the Send+Sync marker | |
454 | transmute::<Box<Error>, Box<Error + Send + Sync>>(s) | |
455 | }) | |
456 | } | |
457 | } | |
458 | ||
459 | #[cfg(test)] | |
460 | mod tests { | |
c1a9b12d SL |
461 | use super::Error; |
462 | use fmt; | |
463 | ||
464 | #[derive(Debug, PartialEq)] | |
465 | struct A; | |
466 | #[derive(Debug, PartialEq)] | |
467 | struct B; | |
468 | ||
469 | impl fmt::Display for A { | |
470 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
471 | write!(f, "A") | |
472 | } | |
473 | } | |
474 | impl fmt::Display for B { | |
475 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
476 | write!(f, "B") | |
477 | } | |
478 | } | |
479 | ||
480 | impl Error for A { | |
481 | fn description(&self) -> &str { "A-desc" } | |
482 | } | |
483 | impl Error for B { | |
484 | fn description(&self) -> &str { "A-desc" } | |
485 | } | |
486 | ||
487 | #[test] | |
488 | fn downcasting() { | |
489 | let mut a = A; | |
490 | let mut a = &mut a as &mut (Error + 'static); | |
491 | assert_eq!(a.downcast_ref::<A>(), Some(&A)); | |
492 | assert_eq!(a.downcast_ref::<B>(), None); | |
493 | assert_eq!(a.downcast_mut::<A>(), Some(&mut A)); | |
494 | assert_eq!(a.downcast_mut::<B>(), None); | |
495 | ||
496 | let a: Box<Error> = Box::new(A); | |
497 | match a.downcast::<B>() { | |
498 | Ok(..) => panic!("expected error"), | |
499 | Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A), | |
500 | } | |
501 | } | |
502 | } |