1 pub use self::imp::{Backtrace, InternalBacktrace};
2 
3 #[cfg(feature = "backtrace")]
4 mod imp {
5     extern crate backtrace;
6 
7     use std::cell::UnsafeCell;
8     use std::env;
9     use std::fmt;
10     use std::sync::atomic::{AtomicUsize, Ordering};
11     use std::sync::{Arc, Mutex};
12 
13     /// Internal representation of a backtrace
14     #[doc(hidden)]
15     #[derive(Clone)]
16     pub struct InternalBacktrace {
17         backtrace: Option<Arc<MaybeResolved>>,
18     }
19 
20     struct MaybeResolved {
21         resolved: Mutex<bool>,
22         backtrace: UnsafeCell<Backtrace>,
23     }
24 
25     unsafe impl Send for MaybeResolved {}
26     unsafe impl Sync for MaybeResolved {}
27 
28     pub use self::backtrace::Backtrace;
29 
30     impl InternalBacktrace {
31         /// Returns a backtrace of the current call stack if `RUST_BACKTRACE`
32         /// is set to anything but ``0``, and `None` otherwise.  This is used
33         /// in the generated error implementations.
34         #[doc(hidden)]
new() -> InternalBacktrace35         pub fn new() -> InternalBacktrace {
36             static ENABLED: AtomicUsize = AtomicUsize::new(0);
37 
38             match ENABLED.load(Ordering::SeqCst) {
39                 0 => {
40                     let enabled = match env::var_os("RUST_BACKTRACE") {
41                         Some(ref val) if val != "0" => true,
42                         _ => false,
43                     };
44                     ENABLED.store(enabled as usize + 1, Ordering::SeqCst);
45                     if !enabled {
46                         return InternalBacktrace { backtrace: None };
47                     }
48                 }
49                 1 => return InternalBacktrace { backtrace: None },
50                 _ => {}
51             }
52 
53             InternalBacktrace {
54                 backtrace: Some(Arc::new(MaybeResolved {
55                     resolved: Mutex::new(false),
56                     backtrace: UnsafeCell::new(Backtrace::new_unresolved()),
57                 })),
58             }
59         }
60 
61         /// Acquire the internal backtrace
62         #[doc(hidden)]
as_backtrace(&self) -> Option<&Backtrace>63         pub fn as_backtrace(&self) -> Option<&Backtrace> {
64             let bt = match self.backtrace {
65                 Some(ref bt) => bt,
66                 None => return None,
67             };
68             let mut resolved = bt.resolved.lock().unwrap();
69             unsafe {
70                 if !*resolved {
71                     (*bt.backtrace.get()).resolve();
72                     *resolved = true;
73                 }
74                 Some(&*bt.backtrace.get())
75             }
76         }
77     }
78 
79     impl fmt::Debug for InternalBacktrace {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result80         fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81             f.debug_struct("InternalBacktrace")
82                 .field("backtrace", &self.as_backtrace())
83                 .finish()
84         }
85     }
86 }
87 
88 #[cfg(not(feature = "backtrace"))]
89 mod imp {
90     /// Dummy type used when the `backtrace` feature is disabled.
91     pub type Backtrace = ();
92 
93     /// Internal representation of a backtrace
94     #[doc(hidden)]
95     #[derive(Clone, Debug)]
96     pub struct InternalBacktrace {}
97 
98     impl InternalBacktrace {
99         /// Returns a new backtrace
100         #[doc(hidden)]
new() -> InternalBacktrace101         pub fn new() -> InternalBacktrace {
102             InternalBacktrace {}
103         }
104 
105         /// Returns the internal backtrace
106         #[doc(hidden)]
as_backtrace(&self) -> Option<&Backtrace>107         pub fn as_backtrace(&self) -> Option<&Backtrace> {
108             None
109         }
110     }
111 }
112