1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! [![License BSD-2-Clause](https://img.shields.io/badge/License-BSD--2--Clause-blue.svg)](https://opensource.org/licenses/BSD-2-Clause)
//! [![License MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
//! [![AppVeyor CI](https://ci.appveyor.com/api/projects/status/github/KizzyCode/ebacktrace-rust?svg=true)](https://ci.appveyor.com/project/KizzyCode/ebacktrace-rust)
//! [![docs.rs](https://docs.rs/ebacktrace/badge.svg)](https://docs.rs/ebacktrace)
//! [![crates.io](https://img.shields.io/crates/v/ebacktrace.svg)](https://crates.io/crates/ebacktrace)
//! [![Download numbers](https://img.shields.io/crates/d/ebacktrace.svg)](https://crates.io/crates/ebacktrace)
//! [![dependency status](https://deps.rs/crate/ebacktrace/0.3.0/status.svg)](https://deps.rs/crate/ebacktrace/0.3.0)
//! 
//! 
//! # `ebacktrace`
//! Welcome to `ebacktrace` 🎉
//! 
//! This crate implements a simple error wrapper which captures a backtrace upon creation and can carry an optional textual
//! description of the error.
//! 
//! ## Example
//! ```should_panic
//! use ebacktrace::define_error;
//! use std::fmt::{ self, Display, Formatter };
//! 
//! /// The error kind
//! #[derive(Debug, Copy, Clone)]
//! enum ErrorKind {
//!     MyErrorA,
//!     Testolope
//! }
//! impl Display for ErrorKind {
//!     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
//!         write!(f, "{:#?}", self)
//!     }
//! }
//! // Define our custom error type
//! define_error!(Error);
//! 
//! /// A function that will always fail
//! fn will_fail() -> Result<(), Error<ErrorKind>> {
//!     Err(ErrorKind::Testolope)?
//! }
//! 
//! // Will panic with a nice error
//! if let Err(e) = will_fail() {
//!     eprintln!("Error: {:?}", e);
//!     panic!("Fatal error")
//! }
//! ```
//! 
//! ## Features
//! This crate currently has two feature gates:
//!   - `derive_display` (enabled by default): Use the `Display`-trait for `Etrace<MyType>` using the `Debug`
//!     representation of `MyType` (instead of the `Display` representation). This way you can pretty-print the underlying
//!     error types without the necessity to manually implement the `Display`-trait for them.
//!   - `force_backtrace` (disabled by default): If `force_backtrace` is enable, the backtrace is always captured,
//!     regardless whether `RUST_BACKTRACE` is set or not.


/// Implements a backtrace drop-in replacement until `$crate::backtrace::Backtrace` becomes stable
#[doc(hidden)]
pub mod backtrace;


/// Defines a custom error generic `$name<E>` where `E` is an arbitrary payload type
///
/// _Note:_ We use a macro to define a new type so that crates can easily implement stuff like `From<T>` for their errors
/// which would not be possible if we define the error type here in this crate.
#[macro_export]
macro_rules! define_error {
    ($name:ident) => {
        /// A struct that wraps an error together with a backtrace and an optional description
        pub struct $name<E> {
            err: E,
            desc: std::borrow::Cow<'static, str>,
            backtrace: std::option::Option<$crate::backtrace::Backtrace>
        }
        impl<E> $name<E> {
            /// Captures a backtrace and creates a new error
            pub fn new(err: E, desc: String) -> Self {
                let backtrace = $crate::backtrace::Backtrace::capture();
                let desc = std::borrow::Cow::Owned(desc);
                Self::with_backtrace(err, desc, backtrace)
            }
            /// Captures a backtrace and creates a new error with a static description
            pub fn new_static(err: E, desc: &'static str) -> Self {
                let backtrace = $crate::backtrace::Backtrace::capture();
                let desc = std::borrow::Cow::Borrowed(desc);
                Self::with_backtrace(err, desc, backtrace)
            }
            /// Creates a new error with the given backtrace
            pub const fn with_backtrace(err: E, desc: std::borrow::Cow<'static, str>,
                backtrace: Option<$crate::backtrace::Backtrace>) -> Self
            {
                Self { err, desc, backtrace }
            }

            /// The wrapped error
            pub const fn err(&self) -> &E {
                &self.err
            }
            /// The error description
            pub const fn desc(&self) -> &std::borrow::Cow<'static, str> {
                &self.desc
            }
            // TODO: Replace with `std::error::Error::backtrace` when `std::backtrace::Backtrace` becomes stable
            /// The underlying backtrace
            pub fn backtrace(&self) -> Option<&$crate::backtrace::Backtrace> {
                self.backtrace.as_ref()
            }
        }
        impl<E> std::ops::Deref for $name<E> {
            type Target = E;
            fn deref(&self) -> &Self::Target {
                &self.err
            }
        }
        impl<E> std::convert::From<E> for $name<E> where E: std::fmt::Display {
            fn from(error: E) -> Self {
                let desc = error.to_string();
                Self::new(error, desc)
            }
        }
        // Error
        impl<E> std::error::Error for $name<E> where E: std::error::Error {
            fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
                self.err.source()
            }
            // TODO: Reimplement when `std::backtrace::Backtrace` becomes stable
            /*
            fn backtrace(&self) -> Option<&std::backtrace::Backtrace> {
                Some(&self.backtrace)
            }
            */
        }
        // Debug
        impl<E> std::fmt::Debug for $name<E> where E: std::fmt::Debug {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                f.debug_struct(std::any::type_name::<Self>())
                    .field("err", &self.err)
                    .field("desc", &self.desc)
                    .field("backtrace", &self.backtrace)
                    .finish()
            }
        }
        // Display
        impl<E> std::fmt::Display for $name<E> where E: std::fmt::Display {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                // Write the error and description
                write!(f, "{}", &self.err)?;
                if !self.desc.is_empty() {
                    write!(f, " ({})", &self.desc)?;
                }

                // Print the backtrace if we have any
                if let Some(backtrace) = self.backtrace.as_ref() {
                    writeln!(f)?;
                    writeln!(f)?;
                    writeln!(f, "Backtrace:")?;
                    write!(f, "{}", backtrace)?;
                }
                Ok(())
            }
        }
        // Default
        impl<E> std::default::Default for $name<E> where E: std::default::Default + std::fmt::Display {
            fn default() -> Self {
                Self::from(E::default())
            }
        }
        // Clone
        impl<E> std::clone::Clone for $name<E> where E: std::clone::Clone {
            fn clone(&self) -> Self {
                Self {
                    err: self.err.clone(),
                    desc: self.desc.clone(),
                    backtrace: self.backtrace.clone()
                }
            }
        }
    };
}