1use std::{
2 fmt::Debug,
3 ops::{Deref, DerefMut},
4};
5
6#[cfg(feature = "clean-backtrace")]
7use backtrace::Backtrace;
8#[cfg(not(feature = "clean-backtrace"))]
9use std::backtrace::Backtrace;
10
11pub type Result<T, E> = std::result::Result<T, Backtraced<E>>;
12
13pub struct Backtraced<E> {
14 pub inner: E,
15 backtrace: Backtrace,
16}
17
18impl<E> Debug for Backtraced<E>
19where
20 E: Debug,
21{
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 if f.alternate() {
24 writeln!(
25 f,
26 "{:?}\n\nBacktrace:\n{}",
27 &self.inner,
28 format_backtrace(&self.backtrace)
29 )
30 } else {
31 writeln!(f, "{:?}", &self.inner)
32 }
33 }
34}
35
36impl<E> From<E> for Backtraced<E> {
37 fn from(value: E) -> Self {
38 Backtraced {
39 inner: value,
40 #[cfg(feature = "clean-backtrace")]
41 backtrace: Backtrace::new(),
42 #[cfg(not(feature = "clean-backtrace"))]
43 backtrace: Backtrace::capture(),
44 }
45 }
46}
47
48pub trait ResultBacktrace {
49 fn backtrace(self) -> Self;
50}
51
52impl<T, E> ResultBacktrace for std::result::Result<T, Backtraced<E>> {
53 fn backtrace(self) -> Self {
54 #[cfg(all(feature = "debug-only", not(debug_assertions)))]
55 return self;
56
57 let Err(ref error) = self else {
58 return self;
59 };
60
61 println!("Error backtrace:\n{}", format_backtrace(&error.backtrace));
62
63 self
64 }
65}
66
67#[cfg(not(feature = "clean-backtrace"))]
68fn format_backtrace(backtrace: &Backtrace) -> String {
69 format!("{backtrace:?}")
70}
71
72#[cfg(feature = "clean-backtrace")]
73fn format_backtrace(backtrace: &Backtrace) -> String {
74 let frames = &backtrace.frames()[1..];
75 let bt = Backtrace::new();
76 let current_frames: Vec<_> = bt.frames().iter().map(|f| f.ip()).collect();
77
78 let frames: Vec<_> = frames
79 .iter()
80 .filter(|f| {
82 f.symbols()
83 .get(0)
84 .map(|symbol| {
85 symbol
86 .name()
87 .map(|name| {
88 let formated_name = format!("{:#?}", name);
89 &formated_name != "<T as core::convert::Into<U>>::into"
91 })
92 .unwrap_or(true)
93 })
94 .unwrap_or(true)
95 })
96 .filter(|x| !current_frames.contains(&x.ip()))
98 .cloned()
99 .collect();
100
101 let backtrace: Backtrace = frames.to_vec().into();
102
103 format!("{backtrace:?}")
104}
105
106impl<E> Deref for Backtraced<E> {
109 type Target = E;
110
111 fn deref(&self) -> &Self::Target {
112 &self.inner
113 }
114}
115
116impl<E> DerefMut for Backtraced<E> {
117 fn deref_mut(&mut self) -> &mut E {
118 &mut self.inner
119 }
120}
121
122impl<E: PartialEq> PartialEq for Backtraced<E> {
123 fn eq(&self, other: &Self) -> bool {
124 self.inner == other.inner
125 }
126}