]> git.proxmox.com Git - rustc.git/blame - src/libstd/error.rs
Imported Upstream version 1.3.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;
c34b1796
AL
52use convert::From;
53use fmt::{self, Debug, Display};
bd371182
AL
54use marker::{Send, Sync, Reflect};
55use mem::transmute;
c34b1796 56use num;
bd371182
AL
57use option::Option::{self, Some, None};
58use result::Result::{self, Ok, Err};
59use raw::TraitObject;
c34b1796
AL
60use str;
61use string::{self, String};
62
63/// Base functionality for all errors in Rust.
64#[stable(feature = "rust1", since = "1.0.0")]
bd371182 65pub trait Error: Debug + Display + Reflect {
c34b1796
AL
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 }
bd371182
AL
77
78 /// Get the `TypeId` of `self`
79 #[doc(hidden)]
62682a34 80 #[unstable(feature = "error_type_id",
bd371182
AL
81 reason = "unclear whether to commit to this public implementation detail")]
82 fn type_id(&self) -> TypeId where Self: 'static {
83 TypeId::of::<Self>()
84 }
c34b1796
AL
85}
86
87#[stable(feature = "rust1", since = "1.0.0")]
88impl<'a, E: Error + 'a> From<E> for Box<Error + 'a> {
89 fn from(err: E) -> Box<Error + 'a> {
90 Box::new(err)
91 }
92}
93
94#[stable(feature = "rust1", since = "1.0.0")]
9346a6ac
AL
95impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<Error + Send + Sync + 'a> {
96 fn from(err: E) -> Box<Error + Send + Sync + 'a> {
c34b1796
AL
97 Box::new(err)
98 }
99}
100
101#[stable(feature = "rust1", since = "1.0.0")]
9346a6ac
AL
102impl From<String> for Box<Error + Send + Sync> {
103 fn from(err: String) -> Box<Error + Send + Sync> {
c34b1796
AL
104 #[derive(Debug)]
105 struct StringError(String);
106
107 impl Error for StringError {
108 fn description(&self) -> &str { &self.0 }
109 }
110
111 impl Display for StringError {
112 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113 Display::fmt(&self.0, f)
114 }
115 }
116
9346a6ac
AL
117 Box::new(StringError(err))
118 }
119}
120
121#[stable(feature = "rust1", since = "1.0.0")]
122impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> {
123 fn from(err: &'b str) -> Box<Error + Send + Sync + 'a> {
62682a34 124 From::from(String::from(err))
c34b1796
AL
125 }
126}
127
128#[stable(feature = "rust1", since = "1.0.0")]
129impl Error for str::ParseBoolError {
130 fn description(&self) -> &str { "failed to parse bool" }
131}
132
133#[stable(feature = "rust1", since = "1.0.0")]
134impl Error for str::Utf8Error {
135 fn description(&self) -> &str {
9346a6ac 136 "invalid utf-8: corrupt contents"
c34b1796
AL
137 }
138}
139
140#[stable(feature = "rust1", since = "1.0.0")]
141impl Error for num::ParseIntError {
142 fn description(&self) -> &str {
62682a34 143 self.__description()
c34b1796
AL
144 }
145}
146
147#[stable(feature = "rust1", since = "1.0.0")]
148impl Error for num::ParseFloatError {
149 fn description(&self) -> &str {
d9579d0f 150 self.__description()
c34b1796
AL
151 }
152}
153
154#[stable(feature = "rust1", since = "1.0.0")]
155impl Error for string::FromUtf8Error {
156 fn description(&self) -> &str {
157 "invalid utf-8"
158 }
159}
160
161#[stable(feature = "rust1", since = "1.0.0")]
162impl Error for string::FromUtf16Error {
163 fn description(&self) -> &str {
164 "invalid utf-16"
165 }
166}
167
bd371182
AL
168// copied from any.rs
169impl Error + 'static {
170 /// Returns true if the boxed type is the same as `T`
c1a9b12d 171 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
172 #[inline]
173 pub fn is<T: Error + 'static>(&self) -> bool {
174 // Get TypeId of the type this function is instantiated with
175 let t = TypeId::of::<T>();
176
177 // Get TypeId of the type in the trait object
178 let boxed = self.type_id();
179
180 // Compare both TypeIds on equality
181 t == boxed
182 }
183
184 /// Returns some reference to the boxed value if it is of type `T`, or
185 /// `None` if it isn't.
c1a9b12d 186 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
187 #[inline]
188 pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
189 if self.is::<T>() {
190 unsafe {
191 // Get the raw representation of the trait object
192 let to: TraitObject = transmute(self);
193
194 // Extract the data pointer
195 Some(transmute(to.data))
196 }
197 } else {
198 None
199 }
200 }
201
202 /// Returns some mutable reference to the boxed value if it is of type `T`, or
203 /// `None` if it isn't.
c1a9b12d 204 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
205 #[inline]
206 pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
207 if self.is::<T>() {
208 unsafe {
209 // Get the raw representation of the trait object
210 let to: TraitObject = transmute(self);
211
212 // Extract the data pointer
213 Some(transmute(to.data))
214 }
215 } else {
216 None
217 }
218 }
219}
220
221impl Error + 'static + Send {
222 /// Forwards to the method defined on the type `Any`.
c1a9b12d 223 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
224 #[inline]
225 pub fn is<T: Error + 'static>(&self) -> bool {
226 <Error + 'static>::is::<T>(self)
227 }
228
229 /// Forwards to the method defined on the type `Any`.
c1a9b12d 230 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
231 #[inline]
232 pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
233 <Error + 'static>::downcast_ref::<T>(self)
234 }
235
236 /// Forwards to the method defined on the type `Any`.
c1a9b12d
SL
237 #[stable(feature = "error_downcast", since = "1.3.0")]
238 #[inline]
239 pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
240 <Error + 'static>::downcast_mut::<T>(self)
241 }
242}
243
244impl Error + 'static + Send + Sync {
245 /// Forwards to the method defined on the type `Any`.
246 #[stable(feature = "error_downcast", since = "1.3.0")]
247 #[inline]
248 pub fn is<T: Error + 'static>(&self) -> bool {
249 <Error + 'static>::is::<T>(self)
250 }
251
252 /// Forwards to the method defined on the type `Any`.
253 #[stable(feature = "error_downcast", since = "1.3.0")]
254 #[inline]
255 pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
256 <Error + 'static>::downcast_ref::<T>(self)
257 }
258
259 /// Forwards to the method defined on the type `Any`.
260 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
261 #[inline]
262 pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
263 <Error + 'static>::downcast_mut::<T>(self)
264 }
265}
266
267impl Error {
268 #[inline]
c1a9b12d 269 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182
AL
270 /// Attempt to downcast the box to a concrete type.
271 pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Error>> {
272 if self.is::<T>() {
273 unsafe {
274 // Get the raw representation of the trait object
62682a34 275 let raw = Box::into_raw(self);
bd371182
AL
276 let to: TraitObject =
277 transmute::<*mut Error, TraitObject>(raw);
278
279 // Extract the data pointer
280 Ok(Box::from_raw(to.data as *mut T))
281 }
282 } else {
283 Err(self)
284 }
285 }
286}
287
288impl Error + Send {
289 #[inline]
c1a9b12d 290 #[stable(feature = "error_downcast", since = "1.3.0")]
bd371182 291 /// Attempt to downcast the box to a concrete type.
c1a9b12d
SL
292 pub fn downcast<T: Error + 'static>(self: Box<Self>)
293 -> Result<Box<T>, Box<Error + Send>> {
bd371182
AL
294 let err: Box<Error> = self;
295 <Error>::downcast(err).map_err(|s| unsafe {
296 // reapply the Send marker
297 transmute::<Box<Error>, Box<Error + Send>>(s)
298 })
299 }
300}
c1a9b12d
SL
301
302impl Error + Send + Sync {
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>)
307 -> Result<Box<T>, Box<Self>> {
308 let err: Box<Error> = self;
309 <Error>::downcast(err).map_err(|s| unsafe {
310 // reapply the Send+Sync marker
311 transmute::<Box<Error>, Box<Error + Send + Sync>>(s)
312 })
313 }
314}
315
316#[cfg(test)]
317mod tests {
318 use prelude::v1::*;
319 use super::Error;
320 use fmt;
321
322 #[derive(Debug, PartialEq)]
323 struct A;
324 #[derive(Debug, PartialEq)]
325 struct B;
326
327 impl fmt::Display for A {
328 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
329 write!(f, "A")
330 }
331 }
332 impl fmt::Display for B {
333 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
334 write!(f, "B")
335 }
336 }
337
338 impl Error for A {
339 fn description(&self) -> &str { "A-desc" }
340 }
341 impl Error for B {
342 fn description(&self) -> &str { "A-desc" }
343 }
344
345 #[test]
346 fn downcasting() {
347 let mut a = A;
348 let mut a = &mut a as &mut (Error + 'static);
349 assert_eq!(a.downcast_ref::<A>(), Some(&A));
350 assert_eq!(a.downcast_ref::<B>(), None);
351 assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
352 assert_eq!(a.downcast_mut::<B>(), None);
353
354 let a: Box<Error> = Box::new(A);
355 match a.downcast::<B>() {
356 Ok(..) => panic!("expected error"),
357 Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
358 }
359 }
360}