]>
Commit | Line | Data |
---|---|---|
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 | 50 | use any::TypeId; |
62682a34 | 51 | use boxed::Box; |
54a0048b | 52 | use char; |
c34b1796 | 53 | use fmt::{self, Debug, Display}; |
bd371182 AL |
54 | use marker::{Send, Sync, Reflect}; |
55 | use mem::transmute; | |
c34b1796 | 56 | use num; |
bd371182 | 57 | use raw::TraitObject; |
c34b1796 AL |
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")] | |
bd371182 | 63 | pub 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")] | |
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")] | |
9346a6ac AL |
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> { | |
c34b1796 AL |
96 | Box::new(err) |
97 | } | |
98 | } | |
99 | ||
100 | #[stable(feature = "rust1", since = "1.0.0")] | |
9346a6ac AL |
101 | impl 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")] |
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 | ||
9346a6ac AL |
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> { | |
62682a34 | 132 | From::from(String::from(err)) |
c34b1796 AL |
133 | } |
134 | } | |
135 | ||
92a42be0 SL |
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 | ||
c34b1796 AL |
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 { | |
9346a6ac | 151 | "invalid utf-8: corrupt contents" |
c34b1796 AL |
152 | } |
153 | } | |
154 | ||
155 | #[stable(feature = "rust1", since = "1.0.0")] | |
156 | impl 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")] | |
163 | impl 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")] | |
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 | ||
7453a54e SL |
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 | ||
54a0048b SL |
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 | ||
7453a54e SL |
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 | ||
bd371182 AL |
208 | // copied from any.rs |
209 | impl 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 | ||
261 | impl 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 | ||
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")] | |
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 | ||
307 | impl 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 | ||
328 | impl 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 | |
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 | } |