#[cfg(any(feature="debug_print_trace", feature="backtrace"))]
extern crate backtrace;
pub type Result<T, E> = std::result::Result<T, Trace<E>>;
pub use trace::Trace;
#[cfg(feature="backtrace")]
pub use trace::StackFrame;
#[cfg(any(feature="debug_print_trace", feature="backtrace"))]
mod trace {
use std::fmt;
use std::os::raw;
use std::ops::{Deref, DerefMut};
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::borrow::Cow;
use backtrace;
#[derive(Clone)]
pub struct Trace<T>(T, Vec<*mut raw::c_void>);
impl<T> From<T> for Trace<T> {
#[inline(always)]
fn from(t: T) -> Self {
Trace::new(t)
}
}
impl<T: fmt::Debug> fmt::Debug for Trace<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{:?} at\n", &self.0));
for (i, frame) in resolve(self).into_iter().enumerate() {
try!(write!(f, "{:>4} {:?}\n", i, &frame));
}
Ok(())
}
}
impl<T> Deref for Trace<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> DerefMut for Trace<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T: Hash> Hash for Trace<T> {
fn hash<H>(&self, state: &mut H)
where H: Hasher {
Hash::hash(&self.0, state)
}
}
impl<T: PartialOrd> PartialOrd for Trace<T> {
fn partial_cmp(&self, rhs: &Trace<T>) -> Option<Ordering> {
PartialOrd::partial_cmp(&self.0, &rhs.0)
}
}
impl<T: Ord> Ord for Trace<T> {
fn cmp(&self, rhs: &Self) -> Ordering {
Ord::cmp(&self.0, &rhs.0)
}
}
impl<T: PartialEq> PartialEq<Trace<T>> for Trace<T> {
fn eq(&self, rhs: &Trace<T>) -> bool {
self.0 == rhs.0
}
}
impl<T: Eq> Eq for Trace<T> {}
impl<T> Trace<T> {
#[inline(never)]
pub fn new(t: T) -> Self {
let mut v = Vec::new();
let mut n = 0;
backtrace::trace(&mut |frame| {
if n > 1 {
v.push(frame.ip());
}
n = n + 1;
true
});
Trace(t, v)
}
#[inline(always)]
pub fn unwrap(self) -> T { self.0 }
#[cfg(feature="backtrace")]
pub fn resolve(&self) -> Vec<StackFrame> {
resolve(self)
}
}
fn resolve<T>(t: &Trace<T>) -> Vec<StackFrame> {
t.1.iter().map(|&ip| {
let mut f = StackFrame { ip: ip, name: None, addr: None, file: None, line: None };
backtrace::resolve(ip, &mut |sym| {
f.name = sym.name().map(String::from_utf8_lossy).map(|mangled| {
let mut name = String::new();
match backtrace::demangle(&mut name, &mangled) {
Ok(()) => name,
Err(_) => mangled.into_owned(),
}
});
f.addr = sym.addr();
f.file = sym.filename().map(String::from_utf8_lossy).map(Cow::into_owned);
f.line = sym.lineno();
});
f
}).collect()
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct StackFrame {
pub ip: *mut raw::c_void,
pub name: Option<String>,
pub addr: Option<*mut raw::c_void>,
pub file: Option<String>,
pub line: Option<u32>,
}
impl fmt::Debug for StackFrame {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let n = self.line.map_or(Cow::Borrowed("<unknown>"), |n| Cow::Owned(format!("{}", n)));
write!(f, "{:16p} - {} ({}:{})",
self.ip,
self.name.as_ref().map(Deref::deref).unwrap_or("<unknown>"),
self.file.as_ref().map(Deref::deref).unwrap_or("<unknown>"),
n,
)
}
}
}
#[cfg(not(any(feature="debug_print_trace", feature="backtrace")))]
mod trace {
use std::fmt::{self, Debug};
use std::ops::{Deref, DerefMut};
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Trace<T>(T);
impl<T> Trace<T> {
#[inline(always)]
pub fn new(t: T) -> Self { Trace(t) }
#[inline(always)]
pub fn unwrap(self) -> T { self.0 }
}
impl<T> From<T> for Trace<T> {
#[inline(always)]
fn from(t: T) -> Self {
Trace::new(t)
}
}
impl<T: Debug> Debug for Trace<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.0, f)
}
}
impl<T> Deref for Trace<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> DerefMut for Trace<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
}