error_chain/
backtrace.rs

1pub use self::imp::{Backtrace, InternalBacktrace};
2
3#[cfg(feature = "backtrace")]
4mod 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, ATOMIC_USIZE_INIT, 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)]
35        pub fn new() -> InternalBacktrace {
36            static ENABLED: AtomicUsize = ATOMIC_USIZE_INIT;
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)]
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 {
80        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"))]
89mod 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)]
101        pub fn new() -> InternalBacktrace {
102            InternalBacktrace {}
103        }
104
105        /// Returns the internal backtrace
106        #[doc(hidden)]
107        pub fn as_backtrace(&self) -> Option<&Backtrace> {
108            None
109        }
110    }
111}