ebacktrace/lib.rs
1//! [](https://opensource.org/licenses/BSD-2-Clause)
2//! [](https://opensource.org/licenses/MIT)
3//! [](https://ci.appveyor.com/project/KizzyCode/ebacktrace-rust)
4//! [](https://docs.rs/ebacktrace)
5//! [](https://crates.io/crates/ebacktrace)
6//! [](https://crates.io/crates/ebacktrace)
7//! [](https://deps.rs/crate/ebacktrace/0.3.0)
8//!
9//!
10//! # `ebacktrace`
11//! Welcome to `ebacktrace` 🎉
12//!
13//! This crate implements a simple error wrapper which captures a backtrace upon creation and can carry an optional textual
14//! description of the error.
15//!
16//! ## Example
17//! ```should_panic
18//! use ebacktrace::define_error;
19//! use std::fmt::{ self, Display, Formatter };
20//!
21//! /// The error kind
22//! #[derive(Debug, Copy, Clone)]
23//! enum ErrorKind {
24//! MyErrorA,
25//! Testolope
26//! }
27//! impl Display for ErrorKind {
28//! fn fmt(&self, f: &mut Formatter) -> fmt::Result {
29//! write!(f, "{:#?}", self)
30//! }
31//! }
32//! // Define our custom error type
33//! define_error!(Error);
34//!
35//! /// A function that will always fail
36//! fn will_fail() -> Result<(), Error<ErrorKind>> {
37//! Err(ErrorKind::Testolope)?
38//! }
39//!
40//! // Will panic with a nice error
41//! if let Err(e) = will_fail() {
42//! eprintln!("Error: {:?}", e);
43//! panic!("Fatal error")
44//! }
45//! ```
46//!
47//! ## Features
48//! This crate currently has two feature gates:
49//! - `derive_display` (enabled by default): Use the `Display`-trait for `Etrace<MyType>` using the `Debug`
50//! representation of `MyType` (instead of the `Display` representation). This way you can pretty-print the underlying
51//! error types without the necessity to manually implement the `Display`-trait for them.
52//! - `force_backtrace` (disabled by default): If `force_backtrace` is enable, the backtrace is always captured,
53//! regardless whether `RUST_BACKTRACE` is set or not.
54
55
56/// Implements a backtrace drop-in replacement until `$crate::backtrace::Backtrace` becomes stable
57#[doc(hidden)]
58pub mod backtrace;
59
60
61/// Defines a custom error generic `$name<E>` where `E` is an arbitrary payload type
62///
63/// _Note:_ We use a macro to define a new type so that crates can easily implement stuff like `From<T>` for their errors
64/// which would not be possible if we define the error type here in this crate.
65#[macro_export]
66macro_rules! define_error {
67 ($name:ident) => {
68 /// A struct that wraps an error together with a backtrace and an optional description
69 pub struct $name<E> {
70 err: E,
71 desc: std::borrow::Cow<'static, str>,
72 backtrace: std::option::Option<$crate::backtrace::Backtrace>
73 }
74 impl<E> $name<E> {
75 /// Captures a backtrace and creates a new error
76 pub fn new(err: E, desc: String) -> Self {
77 let backtrace = $crate::backtrace::Backtrace::capture();
78 let desc = std::borrow::Cow::Owned(desc);
79 Self::with_backtrace(err, desc, backtrace)
80 }
81 /// Captures a backtrace and creates a new error with a static description
82 pub fn new_static(err: E, desc: &'static str) -> Self {
83 let backtrace = $crate::backtrace::Backtrace::capture();
84 let desc = std::borrow::Cow::Borrowed(desc);
85 Self::with_backtrace(err, desc, backtrace)
86 }
87 /// Creates a new error with the given backtrace
88 pub const fn with_backtrace(err: E, desc: std::borrow::Cow<'static, str>,
89 backtrace: Option<$crate::backtrace::Backtrace>) -> Self
90 {
91 Self { err, desc, backtrace }
92 }
93
94 /// The wrapped error
95 pub const fn err(&self) -> &E {
96 &self.err
97 }
98 /// The error description
99 pub const fn desc(&self) -> &std::borrow::Cow<'static, str> {
100 &self.desc
101 }
102 // TODO: Replace with `std::error::Error::backtrace` when `std::backtrace::Backtrace` becomes stable
103 /// The underlying backtrace
104 pub fn backtrace(&self) -> Option<&$crate::backtrace::Backtrace> {
105 self.backtrace.as_ref()
106 }
107 }
108 impl<E> std::ops::Deref for $name<E> {
109 type Target = E;
110 fn deref(&self) -> &Self::Target {
111 &self.err
112 }
113 }
114 impl<E> std::convert::From<E> for $name<E> where E: std::fmt::Display {
115 fn from(error: E) -> Self {
116 let desc = error.to_string();
117 Self::new(error, desc)
118 }
119 }
120 // Error
121 impl<E> std::error::Error for $name<E> where E: std::error::Error {
122 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
123 self.err.source()
124 }
125 // TODO: Reimplement when `std::backtrace::Backtrace` becomes stable
126 /*
127 fn backtrace(&self) -> Option<&std::backtrace::Backtrace> {
128 Some(&self.backtrace)
129 }
130 */
131 }
132 // Debug
133 impl<E> std::fmt::Debug for $name<E> where E: std::fmt::Debug {
134 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
135 f.debug_struct(std::any::type_name::<Self>())
136 .field("err", &self.err)
137 .field("desc", &self.desc)
138 .field("backtrace", &self.backtrace)
139 .finish()
140 }
141 }
142 // Display
143 impl<E> std::fmt::Display for $name<E> where E: std::fmt::Display {
144 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
145 // Write the error and description
146 write!(f, "{}", &self.err)?;
147 if !self.desc.is_empty() {
148 write!(f, " ({})", &self.desc)?;
149 }
150
151 // Print the backtrace if we have any
152 if let Some(backtrace) = self.backtrace.as_ref() {
153 writeln!(f)?;
154 writeln!(f)?;
155 writeln!(f, "Backtrace:")?;
156 write!(f, "{}", backtrace)?;
157 }
158 Ok(())
159 }
160 }
161 // Default
162 impl<E> std::default::Default for $name<E> where E: std::default::Default + std::fmt::Display {
163 fn default() -> Self {
164 Self::from(E::default())
165 }
166 }
167 // Clone
168 impl<E> std::clone::Clone for $name<E> where E: std::clone::Clone {
169 fn clone(&self) -> Self {
170 Self {
171 err: self.err.clone(),
172 desc: self.desc.clone(),
173 backtrace: self.backtrace.clone()
174 }
175 }
176 }
177 };
178}