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