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