1use std::borrow::Cow;
2use std::env;
3use std::ffi;
4use std::fmt;
5use std::result;
6use std::sync::atomic;
7
8const RUST_BACKTRACE: &str = "RUST_BACKTRACE";
9
10#[cfg(all(feature = "backtrace", feature = "std"))]
11mod internal {
12 pub const HAS_BACKTRACE: bool = true;
13
14 pub use backtrace::Backtrace;
15}
16
17#[cfg(not(all(feature = "backtrace", feature = "std")))]
18mod internal {
19 pub const HAS_BACKTRACE: bool = false;
20
21 use std::fmt;
22
23 pub struct Backtrace(());
25
26 impl Backtrace {
27 pub fn new() -> Backtrace {
28 Backtrace(())
29 }
30 }
31
32 impl fmt::Debug for Backtrace {
33 fn fmt(&self, _fmt: &mut fmt::Formatter) -> fmt::Result {
34 Ok(())
35 }
36 }
37}
38
39pub use self::internal::{Backtrace, HAS_BACKTRACE};
40
41pub type Result<T> = result::Result<T, Error>;
42
43pub trait ResultExt<T>
45where
46 Self: Sized,
47{
48 fn chain_err<C, D>(self, chain: C) -> Result<T>
49 where
50 C: FnOnce() -> D,
51 D: Into<Error>;
52}
53
54impl<T> ResultExt<T> for result::Result<T, Error> {
55 fn chain_err<C, D>(self, chain: C) -> Result<T>
56 where
57 C: FnOnce() -> D,
58 D: Into<Error>,
59 {
60 match self {
61 Err(e) => {
62 let mut new = chain().into();
63 new.cause = Some(Box::new(e));
64 Err(new)
65 }
66 Ok(value) => Ok(value),
67 }
68 }
69}
70
71#[derive(Debug, Clone)]
72pub struct Causes<'a> {
73 current: Option<&'a Error>,
74}
75
76impl<'a> Iterator for Causes<'a> {
77 type Item = &'a Error;
78
79 fn next(&mut self) -> Option<Self::Item> {
80 if let Some(e) = self.current {
81 self.current = e.cause();
82 return Some(e);
83 }
84
85 None
86 }
87}
88
89pub struct Display<'a> {
93 message: Cow<'a, str>,
94}
95
96impl<'a> fmt::Display for Display<'a> {
97 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
98 fmt.write_str(self.message.as_ref())
99 }
100}
101
102fn is_backtrace_enabled<F: Fn(&str) -> Option<ffi::OsString>>(get_var: F) -> bool {
103 match get_var(RUST_BACKTRACE) {
104 Some(ref val) if val != "0" => true,
105 _ => false,
106 }
107}
108
109pub struct Error {
110 message: Cow<'static, str>,
111 cause: Option<Box<Error>>,
112 suppressed: Vec<Error>,
113 backtrace: Option<Backtrace>,
114}
115
116impl Error {
117 pub fn new<M: Into<Cow<'static, str>>>(message: M) -> Self {
118 Self {
119 message: message.into(),
120 cause: None,
121 suppressed: Vec::new(),
122 backtrace: Self::new_backtrace(),
123 }
124 }
125
126 fn new_backtrace() -> Option<Backtrace> {
127 if !HAS_BACKTRACE {
128 return None;
129 }
130
131 static ENABLED: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
132
133 match ENABLED.load(atomic::Ordering::SeqCst) {
134 0 => {
135 let enabled = is_backtrace_enabled(|var| env::var_os(var));
136
137 ENABLED.store(enabled as usize + 1, atomic::Ordering::SeqCst);
138
139 if !enabled {
140 return None;
141 }
142 }
143 1 => return None,
144 _ => {}
145 }
146
147 return Some(Backtrace::new());
148 }
149
150 pub fn with_suppressed<S: IntoIterator<Item = Error>>(self, suppressed: S) -> Error {
152 Error {
153 suppressed: suppressed.into_iter().collect(),
154 ..self
155 }
156 }
157
158 pub fn display(&self) -> Display {
162 Display {
163 message: Cow::from(self.message.as_ref()),
164 }
165 }
166
167 pub fn backtrace(&self) -> Option<&Backtrace> {
169 self.backtrace.as_ref()
170 }
171
172 pub fn message(&self) -> &str {
174 self.message.as_ref()
175 }
176
177 pub fn cause(&self) -> Option<&Error> {
179 self.cause.as_ref().map(AsRef::as_ref)
180 }
181
182 pub fn suppressed(&self) -> Vec<&Error> {
184 self.suppressed.iter().collect()
185 }
186
187 pub fn causes(&self) -> Causes {
189 Causes {
190 current: Some(self),
191 }
192 }
193}
194
195impl<T> From<T> for Error
196where
197 T: fmt::Display,
198{
199 fn from(value: T) -> Error {
200 Error::new(value.to_string())
201 }
202}
203
204impl fmt::Debug for Error {
205 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
206 fmt.debug_struct("Error")
207 .field("message", &self.message)
208 .finish()
209 }
210}