]> git.lizzy.rs Git - rust.git/blob - src/libstd/error.rs
introduce Guard enum
[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 #![stable(feature = "rust1", since = "1.0.0")]
14
15 // A note about crates and the facade:
16 //
17 // Originally, the `Error` trait was defined in libcore, and the impls
18 // were scattered about. However, coherence objected to this
19 // arrangement, because to create the blanket impls for `Box` required
20 // knowing that `&str: !Error`, and we have no means to deal with that
21 // sort of conflict just now. Therefore, for the time being, we have
22 // moved the `Error` trait into libstd. As we evolve a sol'n to the
23 // coherence challenge (e.g., specialization, neg impls, etc) we can
24 // reconsider what crate these items belong in.
25
26 use alloc::{AllocErr, LayoutErr, CannotReallocInPlace};
27 use any::TypeId;
28 use borrow::Cow;
29 use cell;
30 use char;
31 use core::array;
32 use fmt::{self, Debug, Display};
33 use mem::transmute;
34 use num;
35 use str;
36 use string;
37
38 /// `Error` is a trait representing the basic expectations for error values,
39 /// i.e. values of type `E` in [`Result<T, E>`]. Errors must describe
40 /// themselves through the [`Display`] and [`Debug`] traits, and may provide
41 /// cause chain information:
42 ///
43 /// The [`cause`] method is generally used when errors cross "abstraction
44 /// boundaries", i.e.  when a one module must report an error that is "caused"
45 /// by an error from a lower-level module. This setup makes it possible for the
46 /// high-level module to provide its own errors that do not commit to any
47 /// particular implementation, but also reveal some of its implementation for
48 /// debugging via [`cause`] chains.
49 ///
50 /// [`Result<T, E>`]: ../result/enum.Result.html
51 /// [`Display`]: ../fmt/trait.Display.html
52 /// [`Debug`]: ../fmt/trait.Debug.html
53 /// [`cause`]: trait.Error.html#method.cause
54 #[stable(feature = "rust1", since = "1.0.0")]
55 pub trait Error: Debug + Display {
56     /// **This method is soft-deprecated.**
57     ///
58     /// Although using it won’t cause compilation warning,
59     /// new code should use [`Display`] instead
60     /// and new `impl`s can omit it.
61     ///
62     /// To obtain error description as a string, use `to_string()`.
63     ///
64     /// [`Display`]: ../fmt/trait.Display.html
65     ///
66     /// # Examples
67     ///
68     /// ```
69     /// match "xc".parse::<u32>() {
70     ///     Err(e) => {
71     ///         // Print `e` itself, not `e.description()`.
72     ///         println!("Error: {}", e);
73     ///     }
74     ///     _ => println!("No error"),
75     /// }
76     /// ```
77     #[stable(feature = "rust1", since = "1.0.0")]
78     fn description(&self) -> &str {
79         "description() is deprecated; use Display"
80     }
81
82     /// The lower-level cause of this error, if any.
83     ///
84     /// # Examples
85     ///
86     /// ```
87     /// use std::error::Error;
88     /// use std::fmt;
89     ///
90     /// #[derive(Debug)]
91     /// struct SuperError {
92     ///     side: SuperErrorSideKick,
93     /// }
94     ///
95     /// impl fmt::Display for SuperError {
96     ///     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97     ///         write!(f, "SuperError is here!")
98     ///     }
99     /// }
100     ///
101     /// impl Error for SuperError {
102     ///     fn description(&self) -> &str {
103     ///         "I'm the superhero of errors"
104     ///     }
105     ///
106     ///     fn cause(&self) -> Option<&Error> {
107     ///         Some(&self.side)
108     ///     }
109     /// }
110     ///
111     /// #[derive(Debug)]
112     /// struct SuperErrorSideKick;
113     ///
114     /// impl fmt::Display for SuperErrorSideKick {
115     ///     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116     ///         write!(f, "SuperErrorSideKick is here!")
117     ///     }
118     /// }
119     ///
120     /// impl Error for SuperErrorSideKick {
121     ///     fn description(&self) -> &str {
122     ///         "I'm SuperError side kick"
123     ///     }
124     /// }
125     ///
126     /// fn get_super_error() -> Result<(), SuperError> {
127     ///     Err(SuperError { side: SuperErrorSideKick })
128     /// }
129     ///
130     /// fn main() {
131     ///     match get_super_error() {
132     ///         Err(e) => {
133     ///             println!("Error: {}", e.description());
134     ///             println!("Caused by: {}", e.cause().unwrap());
135     ///         }
136     ///         _ => println!("No error"),
137     ///     }
138     /// }
139     /// ```
140     #[stable(feature = "rust1", since = "1.0.0")]
141     fn cause(&self) -> Option<&dyn Error> { None }
142
143     /// Get the `TypeId` of `self`
144     #[doc(hidden)]
145     #[unstable(feature = "error_type_id",
146                reason = "unclear whether to commit to this public implementation detail",
147                issue = "27745")]
148     fn type_id(&self) -> TypeId where Self: 'static {
149         TypeId::of::<Self>()
150     }
151 }
152
153 #[stable(feature = "rust1", since = "1.0.0")]
154 impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
155     fn from(err: E) -> Box<dyn Error + 'a> {
156         Box::new(err)
157     }
158 }
159
160 #[stable(feature = "rust1", since = "1.0.0")]
161 impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
162     fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
163         Box::new(err)
164     }
165 }
166
167 #[stable(feature = "rust1", since = "1.0.0")]
168 impl From<String> for Box<dyn Error + Send + Sync> {
169     fn from(err: String) -> Box<dyn Error + Send + Sync> {
170         #[derive(Debug)]
171         struct StringError(String);
172
173         impl Error for StringError {
174             fn description(&self) -> &str { &self.0 }
175         }
176
177         impl Display for StringError {
178             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
179                 Display::fmt(&self.0, f)
180             }
181         }
182
183         Box::new(StringError(err))
184     }
185 }
186
187 #[stable(feature = "string_box_error", since = "1.6.0")]
188 impl From<String> for Box<dyn Error> {
189     fn from(str_err: String) -> Box<dyn Error> {
190         let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
191         let err2: Box<dyn Error> = err1;
192         err2
193     }
194 }
195
196 #[stable(feature = "rust1", since = "1.0.0")]
197 impl<'a, 'b> From<&'b str> for Box<dyn Error + Send + Sync + 'a> {
198     fn from(err: &'b str) -> Box<dyn Error + Send + Sync + 'a> {
199         From::from(String::from(err))
200     }
201 }
202
203 #[stable(feature = "string_box_error", since = "1.6.0")]
204 impl<'a> From<&'a str> for Box<dyn Error> {
205     fn from(err: &'a str) -> Box<dyn Error> {
206         From::from(String::from(err))
207     }
208 }
209
210 #[stable(feature = "cow_box_error", since = "1.22.0")]
211 impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
212     fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
213         From::from(String::from(err))
214     }
215 }
216
217 #[stable(feature = "cow_box_error", since = "1.22.0")]
218 impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
219     fn from(err: Cow<'a, str>) -> Box<dyn Error> {
220         From::from(String::from(err))
221     }
222 }
223
224 #[unstable(feature = "never_type", issue = "35121")]
225 impl Error for ! {
226     fn description(&self) -> &str { *self }
227 }
228
229 #[unstable(feature = "allocator_api",
230            reason = "the precise API and guarantees it provides may be tweaked.",
231            issue = "32838")]
232 impl Error for AllocErr {
233     fn description(&self) -> &str {
234         "memory allocation failed"
235     }
236 }
237
238 #[unstable(feature = "allocator_api",
239            reason = "the precise API and guarantees it provides may be tweaked.",
240            issue = "32838")]
241 impl Error for LayoutErr {
242     fn description(&self) -> &str {
243         "invalid parameters to Layout::from_size_align"
244     }
245 }
246
247 #[unstable(feature = "allocator_api",
248            reason = "the precise API and guarantees it provides may be tweaked.",
249            issue = "32838")]
250 impl Error for CannotReallocInPlace {
251     fn description(&self) -> &str {
252         CannotReallocInPlace::description(self)
253     }
254 }
255
256 #[stable(feature = "rust1", since = "1.0.0")]
257 impl Error for str::ParseBoolError {
258     fn description(&self) -> &str { "failed to parse bool" }
259 }
260
261 #[stable(feature = "rust1", since = "1.0.0")]
262 impl Error for str::Utf8Error {
263     fn description(&self) -> &str {
264         "invalid utf-8: corrupt contents"
265     }
266 }
267
268 #[stable(feature = "rust1", since = "1.0.0")]
269 impl Error for num::ParseIntError {
270     fn description(&self) -> &str {
271         self.__description()
272     }
273 }
274
275 #[unstable(feature = "try_from", issue = "33417")]
276 impl Error for num::TryFromIntError {
277     fn description(&self) -> &str {
278         self.__description()
279     }
280 }
281
282 #[unstable(feature = "try_from", issue = "33417")]
283 impl Error for array::TryFromSliceError {
284     fn description(&self) -> &str {
285         self.__description()
286     }
287 }
288
289 #[stable(feature = "rust1", since = "1.0.0")]
290 impl Error for num::ParseFloatError {
291     fn description(&self) -> &str {
292         self.__description()
293     }
294 }
295
296 #[stable(feature = "rust1", since = "1.0.0")]
297 impl Error for string::FromUtf8Error {
298     fn description(&self) -> &str {
299         "invalid utf-8"
300     }
301 }
302
303 #[stable(feature = "rust1", since = "1.0.0")]
304 impl Error for string::FromUtf16Error {
305     fn description(&self) -> &str {
306         "invalid utf-16"
307     }
308 }
309
310 #[stable(feature = "str_parse_error2", since = "1.8.0")]
311 impl Error for string::ParseError {
312     fn description(&self) -> &str {
313         match *self {}
314     }
315 }
316
317 #[stable(feature = "decode_utf16", since = "1.9.0")]
318 impl Error for char::DecodeUtf16Error {
319     fn description(&self) -> &str {
320         "unpaired surrogate found"
321     }
322 }
323
324 #[stable(feature = "box_error", since = "1.8.0")]
325 impl<T: Error> Error for Box<T> {
326     fn description(&self) -> &str {
327         Error::description(&**self)
328     }
329
330     fn cause(&self) -> Option<&dyn Error> {
331         Error::cause(&**self)
332     }
333 }
334
335 #[stable(feature = "fmt_error", since = "1.11.0")]
336 impl Error for fmt::Error {
337     fn description(&self) -> &str {
338         "an error occurred when formatting an argument"
339     }
340 }
341
342 #[stable(feature = "try_borrow", since = "1.13.0")]
343 impl Error for cell::BorrowError {
344     fn description(&self) -> &str {
345         "already mutably borrowed"
346     }
347 }
348
349 #[stable(feature = "try_borrow", since = "1.13.0")]
350 impl Error for cell::BorrowMutError {
351     fn description(&self) -> &str {
352         "already borrowed"
353     }
354 }
355
356 #[unstable(feature = "try_from", issue = "33417")]
357 impl Error for char::CharTryFromError {
358     fn description(&self) -> &str {
359         "converted integer out of range for `char`"
360     }
361 }
362
363 #[stable(feature = "char_from_str", since = "1.20.0")]
364 impl Error for char::ParseCharError {
365     fn description(&self) -> &str {
366         self.__description()
367     }
368 }
369
370 // copied from any.rs
371 impl dyn Error + 'static {
372     /// Returns true if the boxed type is the same as `T`
373     #[stable(feature = "error_downcast", since = "1.3.0")]
374     #[inline]
375     pub fn is<T: Error + 'static>(&self) -> bool {
376         // Get TypeId of the type this function is instantiated with
377         let t = TypeId::of::<T>();
378
379         // Get TypeId of the type in the trait object
380         let boxed = self.type_id();
381
382         // Compare both TypeIds on equality
383         t == boxed
384     }
385
386     /// Returns some reference to the boxed value if it is of type `T`, or
387     /// `None` if it isn't.
388     #[stable(feature = "error_downcast", since = "1.3.0")]
389     #[inline]
390     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
391         if self.is::<T>() {
392             unsafe {
393                 Some(&*(self as *const dyn Error as *const T))
394             }
395         } else {
396             None
397         }
398     }
399
400     /// Returns some mutable reference to the boxed value if it is of type `T`, or
401     /// `None` if it isn't.
402     #[stable(feature = "error_downcast", since = "1.3.0")]
403     #[inline]
404     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
405         if self.is::<T>() {
406             unsafe {
407                 Some(&mut *(self as *mut dyn Error as *mut T))
408             }
409         } else {
410             None
411         }
412     }
413 }
414
415 impl dyn Error + 'static + Send {
416     /// Forwards to the method defined on the type `Any`.
417     #[stable(feature = "error_downcast", since = "1.3.0")]
418     #[inline]
419     pub fn is<T: Error + 'static>(&self) -> bool {
420         <dyn Error + 'static>::is::<T>(self)
421     }
422
423     /// Forwards to the method defined on the type `Any`.
424     #[stable(feature = "error_downcast", since = "1.3.0")]
425     #[inline]
426     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
427         <dyn Error + 'static>::downcast_ref::<T>(self)
428     }
429
430     /// Forwards to the method defined on the type `Any`.
431     #[stable(feature = "error_downcast", since = "1.3.0")]
432     #[inline]
433     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
434         <dyn Error + 'static>::downcast_mut::<T>(self)
435     }
436 }
437
438 impl dyn Error + 'static + Send + Sync {
439     /// Forwards to the method defined on the type `Any`.
440     #[stable(feature = "error_downcast", since = "1.3.0")]
441     #[inline]
442     pub fn is<T: Error + 'static>(&self) -> bool {
443         <dyn Error + 'static>::is::<T>(self)
444     }
445
446     /// Forwards to the method defined on the type `Any`.
447     #[stable(feature = "error_downcast", since = "1.3.0")]
448     #[inline]
449     pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
450         <dyn Error + 'static>::downcast_ref::<T>(self)
451     }
452
453     /// Forwards to the method defined on the type `Any`.
454     #[stable(feature = "error_downcast", since = "1.3.0")]
455     #[inline]
456     pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
457         <dyn Error + 'static>::downcast_mut::<T>(self)
458     }
459 }
460
461 impl dyn Error {
462     #[inline]
463     #[stable(feature = "error_downcast", since = "1.3.0")]
464     /// Attempt to downcast the box to a concrete type.
465     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
466         if self.is::<T>() {
467             unsafe {
468                 let raw: *mut dyn Error = Box::into_raw(self);
469                 Ok(Box::from_raw(raw as *mut T))
470             }
471         } else {
472             Err(self)
473         }
474     }
475 }
476
477 impl dyn Error + Send {
478     #[inline]
479     #[stable(feature = "error_downcast", since = "1.3.0")]
480     /// Attempt to downcast the box to a concrete type.
481     pub fn downcast<T: Error + 'static>(self: Box<Self>)
482                                         -> Result<Box<T>, Box<dyn Error + Send>> {
483         let err: Box<dyn Error> = self;
484         <dyn Error>::downcast(err).map_err(|s| unsafe {
485             // reapply the Send marker
486             transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
487         })
488     }
489 }
490
491 impl dyn Error + Send + Sync {
492     #[inline]
493     #[stable(feature = "error_downcast", since = "1.3.0")]
494     /// Attempt to downcast the box to a concrete type.
495     pub fn downcast<T: Error + 'static>(self: Box<Self>)
496                                         -> Result<Box<T>, Box<Self>> {
497         let err: Box<dyn Error> = self;
498         <dyn Error>::downcast(err).map_err(|s| unsafe {
499             // reapply the Send+Sync marker
500             transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
501         })
502     }
503 }
504
505 #[cfg(test)]
506 mod tests {
507     use super::Error;
508     use fmt;
509
510     #[derive(Debug, PartialEq)]
511     struct A;
512     #[derive(Debug, PartialEq)]
513     struct B;
514
515     impl fmt::Display for A {
516         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
517             write!(f, "A")
518         }
519     }
520     impl fmt::Display for B {
521         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
522             write!(f, "B")
523         }
524     }
525
526     impl Error for A {
527         fn description(&self) -> &str { "A-desc" }
528     }
529     impl Error for B {
530         fn description(&self) -> &str { "A-desc" }
531     }
532
533     #[test]
534     fn downcasting() {
535         let mut a = A;
536         let a = &mut a as &mut (dyn Error + 'static);
537         assert_eq!(a.downcast_ref::<A>(), Some(&A));
538         assert_eq!(a.downcast_ref::<B>(), None);
539         assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
540         assert_eq!(a.downcast_mut::<B>(), None);
541
542         let a: Box<dyn Error> = Box::new(A);
543         match a.downcast::<B>() {
544             Ok(..) => panic!("expected error"),
545             Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
546         }
547     }
548 }