]> git.lizzy.rs Git - rust.git/blob - src/libstd/error.rs
Rollup merge of #30689 - Manishearth:lifetime-bound, r=steveklabnik
[rust.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 convert::From;
53 use fmt::{self, Debug, Display};
54 use marker::{Send, Sync, Reflect};
55 use mem::transmute;
56 use num;
57 use option::Option::{self, Some, None};
58 use result::Result::{self, Ok, Err};
59 use raw::TraitObject;
60 use str;
61 use string::{self, String};
62
63 /// Base functionality for all errors in Rust.
64 #[stable(feature = "rust1", since = "1.0.0")]
65 pub trait Error: Debug + Display + Reflect {
66     /// A short description of the error.
67     ///
68     /// The description should not contain newlines or sentence-ending
69     /// punctuation, to facilitate embedding in larger user-facing
70     /// strings.
71     #[stable(feature = "rust1", since = "1.0.0")]
72     fn description(&self) -> &str;
73
74     /// The lower-level cause of this error, if any.
75     #[stable(feature = "rust1", since = "1.0.0")]
76     fn cause(&self) -> Option<&Error> { None }
77
78     /// Get the `TypeId` of `self`
79     #[doc(hidden)]
80     #[unstable(feature = "error_type_id",
81                reason = "unclear whether to commit to this public implementation detail",
82                issue = "27745")]
83     fn type_id(&self) -> TypeId where Self: 'static {
84         TypeId::of::<Self>()
85     }
86 }
87
88 #[stable(feature = "rust1", since = "1.0.0")]
89 impl<'a, E: Error + 'a> From<E> for Box<Error + 'a> {
90     fn from(err: E) -> Box<Error + 'a> {
91         Box::new(err)
92     }
93 }
94
95 #[stable(feature = "rust1", since = "1.0.0")]
96 impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<Error + Send + Sync + 'a> {
97     fn from(err: E) -> Box<Error + Send + Sync + 'a> {
98         Box::new(err)
99     }
100 }
101
102 #[stable(feature = "rust1", since = "1.0.0")]
103 impl From<String> for Box<Error + Send + Sync> {
104     fn from(err: String) -> Box<Error + Send + Sync> {
105         #[derive(Debug)]
106         struct StringError(String);
107
108         impl Error for StringError {
109             fn description(&self) -> &str { &self.0 }
110         }
111
112         impl Display for StringError {
113             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114                 Display::fmt(&self.0, f)
115             }
116         }
117
118         Box::new(StringError(err))
119     }
120 }
121
122 #[stable(feature = "string_box_error", since = "1.7.0")]
123 impl From<String> for Box<Error> {
124     fn from(str_err: String) -> Box<Error> {
125         let err1: Box<Error + Send + Sync> = From::from(str_err);
126         let err2: Box<Error> = err1;
127         err2
128     }
129 }
130
131 #[stable(feature = "rust1", since = "1.0.0")]
132 impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> {
133     fn from(err: &'b str) -> Box<Error + Send + Sync + 'a> {
134         From::from(String::from(err))
135     }
136 }
137
138 #[stable(feature = "string_box_error", since = "1.7.0")]
139 impl<'a> From<&'a str> for Box<Error> {
140     fn from(err: &'a str) -> Box<Error> {
141         From::from(String::from(err))
142     }
143 }
144
145 #[stable(feature = "rust1", since = "1.0.0")]
146 impl Error for str::ParseBoolError {
147     fn description(&self) -> &str { "failed to parse bool" }
148 }
149
150 #[stable(feature = "rust1", since = "1.0.0")]
151 impl Error for str::Utf8Error {
152     fn description(&self) -> &str {
153         "invalid utf-8: corrupt contents"
154     }
155 }
156
157 #[stable(feature = "rust1", since = "1.0.0")]
158 impl Error for num::ParseIntError {
159     fn description(&self) -> &str {
160         self.__description()
161     }
162 }
163
164 #[stable(feature = "rust1", since = "1.0.0")]
165 impl Error for num::ParseFloatError {
166     fn description(&self) -> &str {
167         self.__description()
168     }
169 }
170
171 #[stable(feature = "rust1", since = "1.0.0")]
172 impl Error for string::FromUtf8Error {
173     fn description(&self) -> &str {
174         "invalid utf-8"
175     }
176 }
177
178 #[stable(feature = "rust1", since = "1.0.0")]
179 impl Error for string::FromUtf16Error {
180     fn description(&self) -> &str {
181         "invalid utf-16"
182     }
183 }
184
185 #[stable(feature = "str_parse_error2", since = "1.8.0")]
186 impl Error for string::ParseError {
187     fn description(&self) -> &str {
188         match *self {}
189     }
190 }
191
192 // copied from any.rs
193 impl Error + 'static {
194     /// Returns true if the boxed type is the same as `T`
195     #[stable(feature = "error_downcast", since = "1.3.0")]
196     #[inline]
197     pub fn is<T: Error + 'static>(&self) -> bool {
198         // Get TypeId of the type this function is instantiated with
199         let t = TypeId::of::<T>();
200
201         // Get TypeId of the type in the trait object
202         let boxed = self.type_id();
203
204         // Compare both TypeIds on equality
205         t == boxed
206     }
207
208     /// Returns some reference to the boxed value if it is of type `T`, or
209     /// `None` if it isn't.
210     #[stable(feature = "error_downcast", since = "1.3.0")]
211     #[inline]
212     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
213         if self.is::<T>() {
214             unsafe {
215                 // Get the raw representation of the trait object
216                 let to: TraitObject = transmute(self);
217
218                 // Extract the data pointer
219                 Some(&*(to.data as *const T))
220             }
221         } else {
222             None
223         }
224     }
225
226     /// Returns some mutable reference to the boxed value if it is of type `T`, or
227     /// `None` if it isn't.
228     #[stable(feature = "error_downcast", since = "1.3.0")]
229     #[inline]
230     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
231         if self.is::<T>() {
232             unsafe {
233                 // Get the raw representation of the trait object
234                 let to: TraitObject = transmute(self);
235
236                 // Extract the data pointer
237                 Some(&mut *(to.data as *const T as *mut T))
238             }
239         } else {
240             None
241         }
242     }
243 }
244
245 impl Error + 'static + Send {
246     /// Forwards to the method defined on the type `Any`.
247     #[stable(feature = "error_downcast", since = "1.3.0")]
248     #[inline]
249     pub fn is<T: Error + 'static>(&self) -> bool {
250         <Error + 'static>::is::<T>(self)
251     }
252
253     /// Forwards to the method defined on the type `Any`.
254     #[stable(feature = "error_downcast", since = "1.3.0")]
255     #[inline]
256     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
257         <Error + 'static>::downcast_ref::<T>(self)
258     }
259
260     /// Forwards to the method defined on the type `Any`.
261     #[stable(feature = "error_downcast", since = "1.3.0")]
262     #[inline]
263     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
264         <Error + 'static>::downcast_mut::<T>(self)
265     }
266 }
267
268 impl Error + 'static + Send + Sync {
269     /// Forwards to the method defined on the type `Any`.
270     #[stable(feature = "error_downcast", since = "1.3.0")]
271     #[inline]
272     pub fn is<T: Error + 'static>(&self) -> bool {
273         <Error + 'static>::is::<T>(self)
274     }
275
276     /// Forwards to the method defined on the type `Any`.
277     #[stable(feature = "error_downcast", since = "1.3.0")]
278     #[inline]
279     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
280         <Error + 'static>::downcast_ref::<T>(self)
281     }
282
283     /// Forwards to the method defined on the type `Any`.
284     #[stable(feature = "error_downcast", since = "1.3.0")]
285     #[inline]
286     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
287         <Error + 'static>::downcast_mut::<T>(self)
288     }
289 }
290
291 impl Error {
292     #[inline]
293     #[stable(feature = "error_downcast", since = "1.3.0")]
294     /// Attempt to downcast the box to a concrete type.
295     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Error>> {
296         if self.is::<T>() {
297             unsafe {
298                 // Get the raw representation of the trait object
299                 let raw = Box::into_raw(self);
300                 let to: TraitObject =
301                     transmute::<*mut Error, TraitObject>(raw);
302
303                 // Extract the data pointer
304                 Ok(Box::from_raw(to.data as *mut T))
305             }
306         } else {
307             Err(self)
308         }
309     }
310 }
311
312 impl Error + Send {
313     #[inline]
314     #[stable(feature = "error_downcast", since = "1.3.0")]
315     /// Attempt to downcast the box to a concrete type.
316     pub fn downcast<T: Error + 'static>(self: Box<Self>)
317                                         -> Result<Box<T>, Box<Error + Send>> {
318         let err: Box<Error> = self;
319         <Error>::downcast(err).map_err(|s| unsafe {
320             // reapply the Send marker
321             transmute::<Box<Error>, Box<Error + Send>>(s)
322         })
323     }
324 }
325
326 impl Error + Send + Sync {
327     #[inline]
328     #[stable(feature = "error_downcast", since = "1.3.0")]
329     /// Attempt to downcast the box to a concrete type.
330     pub fn downcast<T: Error + 'static>(self: Box<Self>)
331                                         -> Result<Box<T>, Box<Self>> {
332         let err: Box<Error> = self;
333         <Error>::downcast(err).map_err(|s| unsafe {
334             // reapply the Send+Sync marker
335             transmute::<Box<Error>, Box<Error + Send + Sync>>(s)
336         })
337     }
338 }
339
340 #[cfg(test)]
341 mod tests {
342     use prelude::v1::*;
343     use super::Error;
344     use fmt;
345
346     #[derive(Debug, PartialEq)]
347     struct A;
348     #[derive(Debug, PartialEq)]
349     struct B;
350
351     impl fmt::Display for A {
352         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
353             write!(f, "A")
354         }
355     }
356     impl fmt::Display for B {
357         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
358             write!(f, "B")
359         }
360     }
361
362     impl Error for A {
363         fn description(&self) -> &str { "A-desc" }
364     }
365     impl Error for B {
366         fn description(&self) -> &str { "A-desc" }
367     }
368
369     #[test]
370     fn downcasting() {
371         let mut a = A;
372         let mut a = &mut a as &mut (Error + 'static);
373         assert_eq!(a.downcast_ref::<A>(), Some(&A));
374         assert_eq!(a.downcast_ref::<B>(), None);
375         assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
376         assert_eq!(a.downcast_mut::<B>(), None);
377
378         let a: Box<Error> = Box::new(A);
379         match a.downcast::<B>() {
380             Ok(..) => panic!("expected error"),
381             Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
382         }
383     }
384 }