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