ebacktrace/
lib.rs

1//! [![License BSD-2-Clause](https://img.shields.io/badge/License-BSD--2--Clause-blue.svg)](https://opensource.org/licenses/BSD-2-Clause)
2//! [![License MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
3//! [![AppVeyor CI](https://ci.appveyor.com/api/projects/status/github/KizzyCode/ebacktrace-rust?svg=true)](https://ci.appveyor.com/project/KizzyCode/ebacktrace-rust)
4//! [![docs.rs](https://docs.rs/ebacktrace/badge.svg)](https://docs.rs/ebacktrace)
5//! [![crates.io](https://img.shields.io/crates/v/ebacktrace.svg)](https://crates.io/crates/ebacktrace)
6//! [![Download numbers](https://img.shields.io/crates/d/ebacktrace.svg)](https://crates.io/crates/ebacktrace)
7//! [![dependency status](https://deps.rs/crate/ebacktrace/0.3.0/status.svg)](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}