summaryrefslogtreecommitdiffstats
path: root/third_party/rust/error-chain/src/backtrace.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/error-chain/src/backtrace.rs')
-rw-r--r--third_party/rust/error-chain/src/backtrace.rs111
1 files changed, 111 insertions, 0 deletions
diff --git a/third_party/rust/error-chain/src/backtrace.rs b/third_party/rust/error-chain/src/backtrace.rs
new file mode 100644
index 0000000000..14be75ce1b
--- /dev/null
+++ b/third_party/rust/error-chain/src/backtrace.rs
@@ -0,0 +1,111 @@
+pub use self::imp::{Backtrace, InternalBacktrace};
+
+#[cfg(feature = "backtrace")]
+mod imp {
+ extern crate backtrace;
+
+ use std::cell::UnsafeCell;
+ use std::env;
+ use std::fmt;
+ use std::sync::atomic::{AtomicUsize, Ordering};
+ use std::sync::{Arc, Mutex};
+
+ /// Internal representation of a backtrace
+ #[doc(hidden)]
+ #[derive(Clone)]
+ pub struct InternalBacktrace {
+ backtrace: Option<Arc<MaybeResolved>>,
+ }
+
+ struct MaybeResolved {
+ resolved: Mutex<bool>,
+ backtrace: UnsafeCell<Backtrace>,
+ }
+
+ unsafe impl Send for MaybeResolved {}
+ unsafe impl Sync for MaybeResolved {}
+
+ pub use self::backtrace::Backtrace;
+
+ impl InternalBacktrace {
+ /// Returns a backtrace of the current call stack if `RUST_BACKTRACE`
+ /// is set to anything but ``0``, and `None` otherwise. This is used
+ /// in the generated error implementations.
+ #[doc(hidden)]
+ pub fn new() -> InternalBacktrace {
+ static ENABLED: AtomicUsize = AtomicUsize::new(0);
+
+ match ENABLED.load(Ordering::SeqCst) {
+ 0 => {
+ let enabled = match env::var_os("RUST_BACKTRACE") {
+ Some(ref val) if val != "0" => true,
+ _ => false,
+ };
+ ENABLED.store(enabled as usize + 1, Ordering::SeqCst);
+ if !enabled {
+ return InternalBacktrace { backtrace: None };
+ }
+ }
+ 1 => return InternalBacktrace { backtrace: None },
+ _ => {}
+ }
+
+ InternalBacktrace {
+ backtrace: Some(Arc::new(MaybeResolved {
+ resolved: Mutex::new(false),
+ backtrace: UnsafeCell::new(Backtrace::new_unresolved()),
+ })),
+ }
+ }
+
+ /// Acquire the internal backtrace
+ #[doc(hidden)]
+ pub fn as_backtrace(&self) -> Option<&Backtrace> {
+ let bt = match self.backtrace {
+ Some(ref bt) => bt,
+ None => return None,
+ };
+ let mut resolved = bt.resolved.lock().unwrap();
+ unsafe {
+ if !*resolved {
+ (*bt.backtrace.get()).resolve();
+ *resolved = true;
+ }
+ Some(&*bt.backtrace.get())
+ }
+ }
+ }
+
+ impl fmt::Debug for InternalBacktrace {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("InternalBacktrace")
+ .field("backtrace", &self.as_backtrace())
+ .finish()
+ }
+ }
+}
+
+#[cfg(not(feature = "backtrace"))]
+mod imp {
+ /// Dummy type used when the `backtrace` feature is disabled.
+ pub type Backtrace = ();
+
+ /// Internal representation of a backtrace
+ #[doc(hidden)]
+ #[derive(Clone, Debug)]
+ pub struct InternalBacktrace {}
+
+ impl InternalBacktrace {
+ /// Returns a new backtrace
+ #[doc(hidden)]
+ pub fn new() -> InternalBacktrace {
+ InternalBacktrace {}
+ }
+
+ /// Returns the internal backtrace
+ #[doc(hidden)]
+ pub fn as_backtrace(&self) -> Option<&Backtrace> {
+ None
+ }
+ }
+}