drone_mirror_failure/error/
mod.rs

1use core::fmt::{self, Display, Debug};
2
3use {Causes, Fail};
4use backtrace::Backtrace;
5use context::Context;
6use compat::Compat;
7
8#[cfg(feature = "std")]
9use box_std::BoxStd;
10
11#[cfg_attr(feature = "small-error", path = "./error_impl_small.rs")]
12mod error_impl;
13use self::error_impl::ErrorImpl;
14
15#[cfg(feature = "std")]
16use std::error::Error as StdError;
17
18
19/// The `Error` type, which can contain any failure.
20///
21/// Functions which accumulate many kinds of errors should return this type.
22/// All failures can be converted into it, so functions which catch those
23/// errors can be tried with `?` inside of a function that returns this kind
24/// of error.
25///
26/// In addition to implementing `Debug` and `Display`, this type carries `Backtrace`
27/// information, and can be downcast into the failure that underlies it for
28/// more detailed inspection.
29pub struct Error {
30    imp: ErrorImpl,
31}
32
33impl<F: Fail> From<F> for Error {
34    fn from(failure: F) -> Error {
35        Error {
36            imp: ErrorImpl::from(failure)
37        }
38    }
39}
40
41impl Error {
42    /// Creates an `Error` from `Box<std::error::Error>`.
43    ///
44    /// This method is useful for comparability with code,
45    /// which does not use the `Fail` trait.
46    ///
47    /// # Example
48    ///
49    /// ```
50    /// extern crate drone_mirror_failure as failure;
51    ///
52    /// use std::error::Error as StdError;
53    /// use failure::Error;
54    ///
55    /// fn app_fn() -> Result<i32, Error> {
56    ///     let x = library_fn().map_err(Error::from_boxed_compat)?;
57    ///     Ok(x * 2)
58    /// }
59    ///
60    /// fn library_fn() -> Result<i32, Box<StdError + Sync + Send + 'static>> {
61    ///     Ok(92)
62    /// }
63    /// ```
64    #[cfg(feature = "std")]
65    pub fn from_boxed_compat(err: Box<StdError + Sync + Send + 'static>) -> Error {
66        Error::from(BoxStd(err))
67    }
68
69    /// Return a reference to the underlying failure that this `Error`
70    /// contains.
71    pub fn as_fail(&self) -> &Fail {
72        self.imp.failure()
73    }
74
75    /// Returns a reference to the underlying cause of this `Error`. Unlike the
76    /// method on `Fail`, this does not return an `Option`. The `Error` type
77    /// always has an underlying failure.
78    ///
79    /// This method has been deprecated in favor of the [Error::as_fail] method,
80    /// which does the same thing.
81    #[deprecated(since = "0.1.2", note = "please use 'as_fail()' method instead")]
82    pub fn cause(&self) -> &Fail {
83        self.as_fail()
84    }
85
86    /// Gets a reference to the `Backtrace` for this `Error`.
87    ///
88    /// If the failure this wrapped carried a backtrace, that backtrace will
89    /// be returned. Otherwise, the backtrace will have been constructed at
90    /// the point that failure was cast into the `Error` type.
91    pub fn backtrace(&self) -> &Backtrace {
92        self.imp.failure().backtrace().unwrap_or(&self.imp.backtrace())
93    }
94
95    /// Provides context for this `Error`.
96    ///
97    /// This can provide additional information about this error, appropriate
98    /// to the semantics of the current layer. That is, if you have a
99    /// lower-level error, such as an IO error, you can provide additional context
100    /// about what that error means in the context of your function. This
101    /// gives users of this function more information about what has gone
102    /// wrong.
103    ///
104    /// This takes any type that implements `Display`, as well as
105    /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String`
106    /// or a string literal, or a failure, or some other custom context-carrying
107    /// type.
108    pub fn context<D: Display + Send + Sync + 'static>(self, context: D) -> Context<D> {
109        Context::with_err(context, self)
110    }
111
112    /// Wraps `Error` in a compatibility type.
113    ///
114    /// This type implements the `Error` trait from `std::error`. If you need
115    /// to pass failure's `Error` to an interface that takes any `Error`, you
116    /// can use this method to get a compatible type.
117    pub fn compat(self) -> Compat<Error> {
118        Compat { error: self }
119    }
120
121    /// Attempts to downcast this `Error` to a particular `Fail` type.
122    ///
123    /// This downcasts by value, returning an owned `T` if the underlying
124    /// failure is of the type `T`. For this reason it returns a `Result` - in
125    /// the case that the underlying error is of a different type, the
126    /// original `Error` is returned.
127    pub fn downcast<T: Fail>(self) -> Result<T, Error> {
128        self.imp.downcast().map_err(|imp| Error { imp })
129    }
130
131    /// Returns the "root cause" of this error - the last value in the
132    /// cause chain which does not return an underlying `cause`.
133    pub fn find_root_cause(&self) -> &Fail {
134        self.as_fail().find_root_cause()
135    }
136
137    /// Returns a iterator over the causes of this error with the cause
138    /// of the fail as the first item and the `root_cause` as the final item.
139    ///
140    /// Use `iter_chain` to also include the fail of this error itself.
141    pub fn iter_causes(&self) -> Causes {
142        self.as_fail().iter_causes()
143    }
144
145    /// Returns a iterator over all fails up the chain from the current
146    /// as the first item up to the `root_cause` as the final item.
147    ///
148    /// This means that the chain also includes the fail itself which
149    /// means that it does *not* start with `cause`.  To skip the outermost
150    /// fail use `iter_causes` instead.
151    pub fn iter_chain(&self) -> Causes {
152        self.as_fail().iter_chain()
153    }
154
155    /// Attempts to downcast this `Error` to a particular `Fail` type by
156    /// reference.
157    ///
158    /// If the underlying error is not of type `T`, this will return `None`.
159    pub fn downcast_ref<T: Fail>(&self) -> Option<&T> {
160        self.imp.failure().downcast_ref()
161    }
162
163    /// Attempts to downcast this `Error` to a particular `Fail` type by
164    /// mutable reference.
165    ///
166    /// If the underlying error is not of type `T`, this will return `None`.
167    pub fn downcast_mut<T: Fail>(&mut self) -> Option<&mut T> {
168        self.imp.failure_mut().downcast_mut()
169    }
170
171    /// Deprecated alias to `find_root_cause`.
172    #[deprecated(since = "0.1.2", note = "please use the 'find_root_cause()' method instead")]
173    pub fn root_cause(&self) -> &Fail {
174        ::find_root_cause(self.as_fail())
175    }
176
177    /// Deprecated alias to `iter_causes`.
178    #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")]
179    pub fn causes(&self) -> Causes {
180        Causes { fail: Some(self.as_fail()) }
181    }
182}
183
184impl Display for Error {
185    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186        Display::fmt(&self.imp.failure(), f)
187    }
188}
189
190impl Debug for Error {
191    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192        let backtrace = self.imp.backtrace();
193        if backtrace.is_none() {
194            Debug::fmt(&self.imp.failure(), f)
195        } else {
196            write!(f, "{:?}\n\n{:?}", &self.imp.failure(), backtrace)
197        }
198    }
199}
200
201impl AsRef<Fail> for Error {
202    fn as_ref(&self) -> &Fail {
203        self.as_fail()
204    }
205}
206
207#[cfg(test)]
208mod test {
209    use std::io;
210    use super::Error;
211
212    fn assert_just_data<T: Send + Sync + 'static>() { }
213
214    #[test]
215    fn assert_error_is_just_data() {
216        assert_just_data::<Error>();
217    }
218
219    #[test]
220    fn methods_seem_to_work() {
221        let io_error: io::Error = io::Error::new(io::ErrorKind::NotFound, "test");
222        let error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into();
223        assert!(error.downcast_ref::<io::Error>().is_some());
224        let _: ::Backtrace = *error.backtrace();
225        assert_eq!(format!("{:?}", io_error), format!("{:?}", error));
226        assert_eq!(format!("{}", io_error), format!("{}", error));
227        drop(error);
228        assert!(true);
229    }
230}