]> git.lizzy.rs Git - rust.git/blob - src/libstd/error.rs
Rollup merge of #30591 - SimonSapin:patch-15, r=aturon
[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 // copied from any.rs
186 impl Error + 'static {
187     /// Returns true if the boxed type is the same as `T`
188     #[stable(feature = "error_downcast", since = "1.3.0")]
189     #[inline]
190     pub fn is<T: Error + 'static>(&self) -> bool {
191         // Get TypeId of the type this function is instantiated with
192         let t = TypeId::of::<T>();
193
194         // Get TypeId of the type in the trait object
195         let boxed = self.type_id();
196
197         // Compare both TypeIds on equality
198         t == boxed
199     }
200
201     /// Returns some reference to the boxed value if it is of type `T`, or
202     /// `None` if it isn't.
203     #[stable(feature = "error_downcast", since = "1.3.0")]
204     #[inline]
205     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
206         if self.is::<T>() {
207             unsafe {
208                 // Get the raw representation of the trait object
209                 let to: TraitObject = transmute(self);
210
211                 // Extract the data pointer
212                 Some(&*(to.data as *const T))
213             }
214         } else {
215             None
216         }
217     }
218
219     /// Returns some mutable reference to the boxed value if it is of type `T`, or
220     /// `None` if it isn't.
221     #[stable(feature = "error_downcast", since = "1.3.0")]
222     #[inline]
223     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
224         if self.is::<T>() {
225             unsafe {
226                 // Get the raw representation of the trait object
227                 let to: TraitObject = transmute(self);
228
229                 // Extract the data pointer
230                 Some(&mut *(to.data as *const T as *mut T))
231             }
232         } else {
233             None
234         }
235     }
236 }
237
238 impl Error + 'static + Send {
239     /// Forwards to the method defined on the type `Any`.
240     #[stable(feature = "error_downcast", since = "1.3.0")]
241     #[inline]
242     pub fn is<T: Error + 'static>(&self) -> bool {
243         <Error + 'static>::is::<T>(self)
244     }
245
246     /// Forwards to the method defined on the type `Any`.
247     #[stable(feature = "error_downcast", since = "1.3.0")]
248     #[inline]
249     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
250         <Error + 'static>::downcast_ref::<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_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
257         <Error + 'static>::downcast_mut::<T>(self)
258     }
259 }
260
261 impl Error + 'static + Send + Sync {
262     /// Forwards to the method defined on the type `Any`.
263     #[stable(feature = "error_downcast", since = "1.3.0")]
264     #[inline]
265     pub fn is<T: Error + 'static>(&self) -> bool {
266         <Error + 'static>::is::<T>(self)
267     }
268
269     /// Forwards to the method defined on the type `Any`.
270     #[stable(feature = "error_downcast", since = "1.3.0")]
271     #[inline]
272     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
273         <Error + 'static>::downcast_ref::<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_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
280         <Error + 'static>::downcast_mut::<T>(self)
281     }
282 }
283
284 impl Error {
285     #[inline]
286     #[stable(feature = "error_downcast", since = "1.3.0")]
287     /// Attempt to downcast the box to a concrete type.
288     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Error>> {
289         if self.is::<T>() {
290             unsafe {
291                 // Get the raw representation of the trait object
292                 let raw = Box::into_raw(self);
293                 let to: TraitObject =
294                     transmute::<*mut Error, TraitObject>(raw);
295
296                 // Extract the data pointer
297                 Ok(Box::from_raw(to.data as *mut T))
298             }
299         } else {
300             Err(self)
301         }
302     }
303 }
304
305 impl Error + Send {
306     #[inline]
307     #[stable(feature = "error_downcast", since = "1.3.0")]
308     /// Attempt to downcast the box to a concrete type.
309     pub fn downcast<T: Error + 'static>(self: Box<Self>)
310                                         -> Result<Box<T>, Box<Error + Send>> {
311         let err: Box<Error> = self;
312         <Error>::downcast(err).map_err(|s| unsafe {
313             // reapply the Send marker
314             transmute::<Box<Error>, Box<Error + Send>>(s)
315         })
316     }
317 }
318
319 impl Error + Send + Sync {
320     #[inline]
321     #[stable(feature = "error_downcast", since = "1.3.0")]
322     /// Attempt to downcast the box to a concrete type.
323     pub fn downcast<T: Error + 'static>(self: Box<Self>)
324                                         -> Result<Box<T>, Box<Self>> {
325         let err: Box<Error> = self;
326         <Error>::downcast(err).map_err(|s| unsafe {
327             // reapply the Send+Sync marker
328             transmute::<Box<Error>, Box<Error + Send + Sync>>(s)
329         })
330     }
331 }
332
333 #[cfg(test)]
334 mod tests {
335     use prelude::v1::*;
336     use super::Error;
337     use fmt;
338
339     #[derive(Debug, PartialEq)]
340     struct A;
341     #[derive(Debug, PartialEq)]
342     struct B;
343
344     impl fmt::Display for A {
345         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
346             write!(f, "A")
347         }
348     }
349     impl fmt::Display for B {
350         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
351             write!(f, "B")
352         }
353     }
354
355     impl Error for A {
356         fn description(&self) -> &str { "A-desc" }
357     }
358     impl Error for B {
359         fn description(&self) -> &str { "A-desc" }
360     }
361
362     #[test]
363     fn downcasting() {
364         let mut a = A;
365         let mut a = &mut a as &mut (Error + 'static);
366         assert_eq!(a.downcast_ref::<A>(), Some(&A));
367         assert_eq!(a.downcast_ref::<B>(), None);
368         assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
369         assert_eq!(a.downcast_mut::<B>(), None);
370
371         let a: Box<Error> = Box::new(A);
372         match a.downcast::<B>() {
373             Ok(..) => panic!("expected error"),
374             Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
375         }
376     }
377 }