]> git.proxmox.com Git - rustc.git/blame - src/libstd/error.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / libstd / error.rs
CommitLineData
c34b1796
AL
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
bd371182 50use any::TypeId;
62682a34 51use boxed::Box;
54a0048b 52use char;
c34b1796 53use fmt::{self, Debug, Display};
bd371182
AL
54use marker::{Send, Sync, Reflect};
55use mem::transmute;
c34b1796 56use num;
bd371182 57use raw::TraitObject;
c34b1796
AL
58use str;
59use string::{self, String};
60
61/// Base functionality for all errors in Rust.
62#[stable(feature = "rust1", since = "1.0.0")]
bd371182 63pub trait Error: Debug + Display + Reflect {
c34b1796
AL
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 }
bd371182
AL
75
76 /// Get the `TypeId` of `self`
77 #[doc(hidden)]
62682a34 78 #[unstable(feature = "error_type_id",
e9174d1e
SL
79 reason = "unclear whether to commit to this public implementation detail",
80 issue = "27745")]
bd371182
AL
81 fn type_id(&self) -> TypeId where Self: 'static {
82 TypeId::of::<Self>()
83 }
c34b1796
AL
84}
85
86#[stable(feature = "rust1", since = "1.0.0")]
87impl<'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")]
9346a6ac
AL
94impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<Error + Send + Sync + 'a> {
95 fn from(err: E) -> Box<Error + Send + Sync + 'a> {
c34b1796
AL
96 Box::new(err)
97 }
98}
99
100#[stable(feature = "rust1", since = "1.0.0")]
9346a6ac
AL
101impl From<String> for Box<Error + Send + Sync> {
102 fn from(err: String) -> Box<Error + Send + Sync> {
c34b1796
AL
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
9346a6ac
AL
116 Box::new(StringError(err))
117 }
118}
119
92a42be0
SL
120#[stable(feature = "string_box_error", since = "1.7.0")]
121impl 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
9346a6ac
AL
129#[stable(feature = "rust1", since = "1.0.0")]
130impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> {
131 fn from(err: &'b str) -> Box<Error + Send + Sync + 'a> {
62682a34 132 From::from(String::from(err))
c34b1796
AL
133 }
134}
135
92a42be0
SL
136#[stable(feature = "string_box_error", since = "1.7.0")]
137impl<'a> From<&'a str> for Box<Error> {
138 fn from(err: &'a str) -> Box<Error> {
139 From::from(String::from(err))
140 }
141}
142
c34b1796
AL
143#[stable(feature = "rust1", since = "1.0.0")]
144impl Error for str::ParseBoolError {
145 fn description(&self) -> &str { "failed to parse bool" }
146}
147
148#[stable(feature = "rust1", since = "1.0.0")]
149impl Error for str::Utf8Error {
150 fn description(&self) -> &str {
9346a6ac 151 "invalid utf-8: corrupt contents"
c34b1796
AL
152 }
153}
154
155#[stable(feature = "rust1", since = "1.0.0")]
156impl Error for num::ParseIntError {
157 fn description(&self) -> &str {
62682a34 158 self.__description()
c34b1796
AL
159 }
160}
161
162#[stable(feature = "rust1", since = "1.0.0")]
163impl Error for num::ParseFloatError {
164 fn description(&self) -> &str {
d9579d0f 165 self.__description()
c34b1796
AL
166 }
167}
168
169#[stable(feature = "rust1", since = "1.0.0")]
170impl Error for string::FromUtf8Error {
171 fn description(&self) -> &str {
172 "invalid utf-8"
173 }
174}
175
176#[stable(feature = "rust1", since = "1.0.0")]
177impl Error for string::FromUtf16Error {
178 fn description(&self) -> &str {
179 "invalid utf-16"
180 }
181}
182
7453a54e
SL
183#[stable(feature = "str_parse_error2", since = "1.8.0")]
184impl Error for string::ParseError {
185 fn description(&self) -> &str {
186 match *self {}
187 }
188}
189
54a0048b
SL
190#[stable(feature = "decode_utf16", since = "1.9.0")]
191impl Error for char::DecodeUtf16Error {
192 fn description(&self) -> &str {
193 "unpaired surrogate found"
194 }
195}
196
7453a54e
SL
197#[stable(feature = "box_error", since = "1.7.0")]
198impl<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
bd371182
AL
208// copied from any.rs
209impl Error + 'static {
210 /// Returns true if the boxed type is the same as `T`
c1a9b12d 211 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
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.
c1a9b12d 226 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
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
e9174d1e 235 Some(&*(to.data as *const T))
bd371182
AL
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.
c1a9b12d 244 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
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
e9174d1e 253 Some(&mut *(to.data as *const T as *mut T))
bd371182
AL
254 }
255 } else {
256 None
257 }
258 }
259}
260
261impl Error + 'static + Send {
262 /// Forwards to the method defined on the type `Any`.
c1a9b12d 263 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
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`.
c1a9b12d 270 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
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`.
c1a9b12d
SL
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
284impl 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")]
bd371182
AL
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
307impl Error {
308 #[inline]
c1a9b12d 309 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
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
62682a34 315 let raw = Box::into_raw(self);
bd371182
AL
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
328impl Error + Send {
329 #[inline]
c1a9b12d 330 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182 331 /// Attempt to downcast the box to a concrete type.
c1a9b12d
SL
332 pub fn downcast<T: Error + 'static>(self: Box<Self>)
333 -> Result<Box<T>, Box<Error + Send>> {
bd371182
AL
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}
c1a9b12d
SL
341
342impl 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)]
357mod 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}