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()
}
}
}
};
}