alt_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 /// use std::error::Error as StdError;
51 /// use failure::Error;
52 ///
53 /// fn app_fn() -> Result<i32, Error> {
54 /// let x = library_fn().map_err(Error::from_boxed_compat)?;
55 /// Ok(x * 2)
56 /// }
57 ///
58 /// fn library_fn() -> Result<i32, Box<StdError + Sync + Send + 'static>> {
59 /// Ok(92)
60 /// }
61 /// ```
62 #[cfg(feature = "std")]
63 pub fn from_boxed_compat(err: Box<StdError + Sync + Send + 'static>) -> Error {
64 Error::from(BoxStd(err))
65 }
66
67 /// Return a reference to the underlying failure that this `Error`
68 /// contains.
69 pub fn as_fail(&self) -> &Fail {
70 self.imp.failure()
71 }
72
73 /// Returns the name of the underlying fail.
74 pub fn name(&self) -> Option<&str> {
75 self.as_fail().name()
76 }
77
78 /// Returns a reference to the underlying cause of this `Error`. Unlike the
79 /// method on `Fail`, this does not return an `Option`. The `Error` type
80 /// always has an underlying failure.
81 ///
82 /// This method has been deprecated in favor of the [Error::as_fail] method,
83 /// which does the same thing.
84 #[deprecated(since = "0.1.2", note = "please use 'as_fail()' method instead")]
85 pub fn cause(&self) -> &Fail {
86 self.as_fail()
87 }
88
89 /// Gets a reference to the `Backtrace` for this `Error`.
90 ///
91 /// If the failure this wrapped carried a backtrace, that backtrace will
92 /// be returned. Otherwise, the backtrace will have been constructed at
93 /// the point that failure was cast into the `Error` type.
94 pub fn backtrace(&self) -> &Backtrace {
95 self.imp.failure().backtrace().unwrap_or(&self.imp.backtrace())
96 }
97
98 /// Provides context for this `Error`.
99 ///
100 /// This can provide additional information about this error, appropriate
101 /// to the semantics of the current layer. That is, if you have a
102 /// lower-level error, such as an IO error, you can provide additional context
103 /// about what that error means in the context of your function. This
104 /// gives users of this function more information about what has gone
105 /// wrong.
106 ///
107 /// This takes any type that implements `Display`, as well as
108 /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String`
109 /// or a string literal, or a failure, or some other custom context-carrying
110 /// type.
111 pub fn context<D: Display + Send + Sync + 'static>(self, context: D) -> Context<D> {
112 Context::with_err(context, self)
113 }
114
115 /// Wraps `Error` in a compatibility type.
116 ///
117 /// This type implements the `Error` trait from `std::error`. If you need
118 /// to pass failure's `Error` to an interface that takes any `Error`, you
119 /// can use this method to get a compatible type.
120 pub fn compat(self) -> Compat<Error> {
121 Compat { error: self }
122 }
123
124 /// Attempts to downcast this `Error` to a particular `Fail` type.
125 ///
126 /// This downcasts by value, returning an owned `T` if the underlying
127 /// failure is of the type `T`. For this reason it returns a `Result` - in
128 /// the case that the underlying error is of a different type, the
129 /// original `Error` is returned.
130 pub fn downcast<T: Fail>(self) -> Result<T, Error> {
131 self.imp.downcast().map_err(|imp| Error { imp })
132 }
133
134 /// Returns the "root cause" of this error - the last value in the
135 /// cause chain which does not return an underlying `cause`.
136 pub fn find_root_cause(&self) -> &Fail {
137 self.as_fail().find_root_cause()
138 }
139
140 /// Returns a iterator over the causes of this error with the cause
141 /// of the fail as the first item and the `root_cause` as the final item.
142 ///
143 /// Use `iter_chain` to also include the fail of this error itself.
144 pub fn iter_causes(&self) -> Causes {
145 self.as_fail().iter_causes()
146 }
147
148 /// Returns a iterator over all fails up the chain from the current
149 /// as the first item up to the `root_cause` as the final item.
150 ///
151 /// This means that the chain also includes the fail itself which
152 /// means that it does *not* start with `cause`. To skip the outermost
153 /// fail use `iter_causes` instead.
154 pub fn iter_chain(&self) -> Causes {
155 self.as_fail().iter_chain()
156 }
157
158 /// Attempts to downcast this `Error` to a particular `Fail` type by
159 /// reference.
160 ///
161 /// If the underlying error is not of type `T`, this will return `None`.
162 pub fn downcast_ref<T: Fail>(&self) -> Option<&T> {
163 self.imp.failure().downcast_ref()
164 }
165
166 /// Attempts to downcast this `Error` to a particular `Fail` type by
167 /// mutable reference.
168 ///
169 /// If the underlying error is not of type `T`, this will return `None`.
170 pub fn downcast_mut<T: Fail>(&mut self) -> Option<&mut T> {
171 self.imp.failure_mut().downcast_mut()
172 }
173
174 /// Deprecated alias to `find_root_cause`.
175 #[deprecated(since = "0.1.2", note = "please use the 'find_root_cause()' method instead")]
176 pub fn root_cause(&self) -> &Fail {
177 ::find_root_cause(self.as_fail())
178 }
179
180 /// Deprecated alias to `iter_causes`.
181 #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")]
182 pub fn causes(&self) -> Causes {
183 Causes { fail: Some(self.as_fail()) }
184 }
185}
186
187impl Display for Error {
188 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189 Display::fmt(&self.imp.failure(), f)
190 }
191}
192
193impl Debug for Error {
194 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
195 let backtrace = self.imp.backtrace();
196 if backtrace.is_none() {
197 Debug::fmt(&self.imp.failure(), f)
198 } else {
199 write!(f, "{:?}\n\n{:?}", &self.imp.failure(), backtrace)
200 }
201 }
202}
203
204impl AsRef<Fail> for Error {
205 fn as_ref(&self) -> &Fail {
206 self.as_fail()
207 }
208}
209
210#[cfg(test)]
211mod test {
212 use std::io;
213 use super::Error;
214
215 fn assert_just_data<T: Send + Sync + 'static>() { }
216
217 #[test]
218 fn assert_error_is_just_data() {
219 assert_just_data::<Error>();
220 }
221
222 #[test]
223 fn methods_seem_to_work() {
224 let io_error: io::Error = io::Error::new(io::ErrorKind::NotFound, "test");
225 let error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into();
226 assert!(error.downcast_ref::<io::Error>().is_some());
227 let _: ::Backtrace = *error.backtrace();
228 assert_eq!(format!("{:?}", io_error), format!("{:?}", error));
229 assert_eq!(format!("{}", io_error), format!("{}", error));
230 drop(error);
231 assert!(true);
232 }
233
234 #[test]
235 fn downcast_can_be_used() {
236 let mut error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into();
237 {
238 let real_io_error_ref = error.downcast_ref::<io::Error>().unwrap();
239 assert_eq!(real_io_error_ref.to_string(), "test");
240 }
241 {
242 let real_io_error_mut = error.downcast_mut::<io::Error>().unwrap();
243 assert_eq!(real_io_error_mut.to_string(), "test");
244 }
245 let real_io_error = error.downcast::<io::Error>().unwrap();
246 assert_eq!(real_io_error.to_string(), "test");
247 }
248}