]> git.lizzy.rs Git - rust.git/blob - src/libstd/error.rs
Auto merge of #30595 - steveklabnik:remove_learn_rust, r=gankro
[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 = "rust1", since = "1.0.0")]
123 impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> {
124     fn from(err: &'b str) -> Box<Error + Send + Sync + 'a> {
125         From::from(String::from(err))
126     }
127 }
128
129 #[stable(feature = "rust1", since = "1.0.0")]
130 impl Error for str::ParseBoolError {
131     fn description(&self) -> &str { "failed to parse bool" }
132 }
133
134 #[stable(feature = "rust1", since = "1.0.0")]
135 impl Error for str::Utf8Error {
136     fn description(&self) -> &str {
137         "invalid utf-8: corrupt contents"
138     }
139 }
140
141 #[stable(feature = "rust1", since = "1.0.0")]
142 impl Error for num::ParseIntError {
143     fn description(&self) -> &str {
144         self.__description()
145     }
146 }
147
148 #[stable(feature = "rust1", since = "1.0.0")]
149 impl Error for num::ParseFloatError {
150     fn description(&self) -> &str {
151         self.__description()
152     }
153 }
154
155 #[stable(feature = "rust1", since = "1.0.0")]
156 impl Error for string::FromUtf8Error {
157     fn description(&self) -> &str {
158         "invalid utf-8"
159     }
160 }
161
162 #[stable(feature = "rust1", since = "1.0.0")]
163 impl Error for string::FromUtf16Error {
164     fn description(&self) -> &str {
165         "invalid utf-16"
166     }
167 }
168
169 // copied from any.rs
170 impl Error + 'static {
171     /// Returns true if the boxed type is the same as `T`
172     #[stable(feature = "error_downcast", since = "1.3.0")]
173     #[inline]
174     pub fn is<T: Error + 'static>(&self) -> bool {
175         // Get TypeId of the type this function is instantiated with
176         let t = TypeId::of::<T>();
177
178         // Get TypeId of the type in the trait object
179         let boxed = self.type_id();
180
181         // Compare both TypeIds on equality
182         t == boxed
183     }
184
185     /// Returns some reference to the boxed value if it is of type `T`, or
186     /// `None` if it isn't.
187     #[stable(feature = "error_downcast", since = "1.3.0")]
188     #[inline]
189     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
190         if self.is::<T>() {
191             unsafe {
192                 // Get the raw representation of the trait object
193                 let to: TraitObject = transmute(self);
194
195                 // Extract the data pointer
196                 Some(&*(to.data as *const T))
197             }
198         } else {
199             None
200         }
201     }
202
203     /// Returns some mutable reference to the boxed value if it is of type `T`, or
204     /// `None` if it isn't.
205     #[stable(feature = "error_downcast", since = "1.3.0")]
206     #[inline]
207     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
208         if self.is::<T>() {
209             unsafe {
210                 // Get the raw representation of the trait object
211                 let to: TraitObject = transmute(self);
212
213                 // Extract the data pointer
214                 Some(&mut *(to.data as *const T as *mut T))
215             }
216         } else {
217             None
218         }
219     }
220 }
221
222 impl Error + 'static + Send {
223     /// Forwards to the method defined on the type `Any`.
224     #[stable(feature = "error_downcast", since = "1.3.0")]
225     #[inline]
226     pub fn is<T: Error + 'static>(&self) -> bool {
227         <Error + 'static>::is::<T>(self)
228     }
229
230     /// Forwards to the method defined on the type `Any`.
231     #[stable(feature = "error_downcast", since = "1.3.0")]
232     #[inline]
233     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
234         <Error + 'static>::downcast_ref::<T>(self)
235     }
236
237     /// Forwards to the method defined on the type `Any`.
238     #[stable(feature = "error_downcast", since = "1.3.0")]
239     #[inline]
240     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
241         <Error + 'static>::downcast_mut::<T>(self)
242     }
243 }
244
245 impl Error + 'static + Send + Sync {
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 {
269     #[inline]
270     #[stable(feature = "error_downcast", since = "1.3.0")]
271     /// Attempt to downcast the box to a concrete type.
272     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Error>> {
273         if self.is::<T>() {
274             unsafe {
275                 // Get the raw representation of the trait object
276                 let raw = Box::into_raw(self);
277                 let to: TraitObject =
278                     transmute::<*mut Error, TraitObject>(raw);
279
280                 // Extract the data pointer
281                 Ok(Box::from_raw(to.data as *mut T))
282             }
283         } else {
284             Err(self)
285         }
286     }
287 }
288
289 impl Error + Send {
290     #[inline]
291     #[stable(feature = "error_downcast", since = "1.3.0")]
292     /// Attempt to downcast the box to a concrete type.
293     pub fn downcast<T: Error + 'static>(self: Box<Self>)
294                                         -> Result<Box<T>, Box<Error + Send>> {
295         let err: Box<Error> = self;
296         <Error>::downcast(err).map_err(|s| unsafe {
297             // reapply the Send marker
298             transmute::<Box<Error>, Box<Error + Send>>(s)
299         })
300     }
301 }
302
303 impl Error + Send + Sync {
304     #[inline]
305     #[stable(feature = "error_downcast", since = "1.3.0")]
306     /// Attempt to downcast the box to a concrete type.
307     pub fn downcast<T: Error + 'static>(self: Box<Self>)
308                                         -> Result<Box<T>, Box<Self>> {
309         let err: Box<Error> = self;
310         <Error>::downcast(err).map_err(|s| unsafe {
311             // reapply the Send+Sync marker
312             transmute::<Box<Error>, Box<Error + Send + Sync>>(s)
313         })
314     }
315 }
316
317 #[cfg(test)]
318 mod tests {
319     use prelude::v1::*;
320     use super::Error;
321     use fmt;
322
323     #[derive(Debug, PartialEq)]
324     struct A;
325     #[derive(Debug, PartialEq)]
326     struct B;
327
328     impl fmt::Display for A {
329         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
330             write!(f, "A")
331         }
332     }
333     impl fmt::Display for B {
334         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
335             write!(f, "B")
336         }
337     }
338
339     impl Error for A {
340         fn description(&self) -> &str { "A-desc" }
341     }
342     impl Error for B {
343         fn description(&self) -> &str { "A-desc" }
344     }
345
346     #[test]
347     fn downcasting() {
348         let mut a = A;
349         let mut a = &mut a as &mut (Error + 'static);
350         assert_eq!(a.downcast_ref::<A>(), Some(&A));
351         assert_eq!(a.downcast_ref::<B>(), None);
352         assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
353         assert_eq!(a.downcast_mut::<B>(), None);
354
355         let a: Box<Error> = Box::new(A);
356         match a.downcast::<B>() {
357             Ok(..) => panic!("expected error"),
358             Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
359         }
360     }
361 }