diff options
Diffstat (limited to 'third_party/rust/failure/src')
-rw-r--r-- | third_party/rust/failure/src/as_fail.rs | 37 | ||||
-rw-r--r-- | third_party/rust/failure/src/backtrace/internal.rs | 132 | ||||
-rw-r--r-- | third_party/rust/failure/src/backtrace/mod.rs | 159 | ||||
-rw-r--r-- | third_party/rust/failure/src/box_std.rs | 19 | ||||
-rw-r--r-- | third_party/rust/failure/src/compat.rs | 53 | ||||
-rw-r--r-- | third_party/rust/failure/src/context.rs | 180 | ||||
-rw-r--r-- | third_party/rust/failure/src/error/error_impl.rs | 50 | ||||
-rw-r--r-- | third_party/rust/failure/src/error/error_impl_small.rs | 132 | ||||
-rw-r--r-- | third_party/rust/failure/src/error/mod.rs | 248 | ||||
-rw-r--r-- | third_party/rust/failure/src/error_message.rs | 32 | ||||
-rw-r--r-- | third_party/rust/failure/src/lib.rs | 307 | ||||
-rw-r--r-- | third_party/rust/failure/src/macros.rs | 64 | ||||
-rw-r--r-- | third_party/rust/failure/src/result_ext.rs | 203 | ||||
-rw-r--r-- | third_party/rust/failure/src/small_error.rs | 264 | ||||
-rw-r--r-- | third_party/rust/failure/src/sync_failure.rs | 97 |
15 files changed, 1977 insertions, 0 deletions
diff --git a/third_party/rust/failure/src/as_fail.rs b/third_party/rust/failure/src/as_fail.rs new file mode 100644 index 0000000000..6e4172bd8c --- /dev/null +++ b/third_party/rust/failure/src/as_fail.rs @@ -0,0 +1,37 @@ +use Fail; + +/// The `AsFail` trait +/// +/// This trait is similar to `AsRef<Fail>`, but it is specialized to handle +/// the dynamic object of `Fail`. Implementors of `Fail` have a blanket +/// implementation. It is used in `failure_derive` in order to generate a +/// custom cause. +pub trait AsFail { + /// Converts a reference to `Self` into a dynamic trait object of `Fail`. + fn as_fail(&self) -> &dyn Fail; +} + +impl<T> AsFail for T +where + T: Fail, +{ + fn as_fail(&self) -> &dyn Fail { + self + } +} + +impl AsFail for dyn Fail { + fn as_fail(&self) -> &dyn Fail { + self + } +} + +with_std! { + use error::Error; + + impl AsFail for Error { + fn as_fail(&self) -> &dyn Fail { + self.as_fail() + } + } +} diff --git a/third_party/rust/failure/src/backtrace/internal.rs b/third_party/rust/failure/src/backtrace/internal.rs new file mode 100644 index 0000000000..5e421201fa --- /dev/null +++ b/third_party/rust/failure/src/backtrace/internal.rs @@ -0,0 +1,132 @@ +use std::cell::UnsafeCell; +use std::env; +use std::ffi::OsString; +use std::fmt; +#[allow(deprecated)] // to allow for older Rust versions (<1.24) +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; +use std::sync::Mutex; + +pub use super::backtrace::Backtrace; + +const GENERAL_BACKTRACE: &str = "RUST_BACKTRACE"; +const FAILURE_BACKTRACE: &str = "RUST_FAILURE_BACKTRACE"; + +pub(super) struct InternalBacktrace { + backtrace: Option<MaybeResolved>, +} + +struct MaybeResolved { + resolved: Mutex<bool>, + backtrace: UnsafeCell<Backtrace>, +} + +unsafe impl Send for MaybeResolved {} +unsafe impl Sync for MaybeResolved {} + +impl InternalBacktrace { + pub(super) fn new() -> InternalBacktrace { + #[allow(deprecated)] // to allow for older Rust versions (<1.24) + static ENABLED: AtomicUsize = ATOMIC_USIZE_INIT; + + match ENABLED.load(Ordering::SeqCst) { + 0 => { + let enabled = is_backtrace_enabled(|var| env::var_os(var)); + ENABLED.store(enabled as usize + 1, Ordering::SeqCst); + if !enabled { + return InternalBacktrace { backtrace: None } + } + } + 1 => return InternalBacktrace { backtrace: None }, + _ => {} + } + + InternalBacktrace { + backtrace: Some(MaybeResolved { + resolved: Mutex::new(false), + backtrace: UnsafeCell::new(Backtrace::new_unresolved()), + }), + } + } + + pub(super) fn none() -> InternalBacktrace { + InternalBacktrace { backtrace: None } + } + + pub(super) 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()) + } + } + + pub(super) fn is_none(&self) -> bool { + self.backtrace.is_none() + } +} + +impl fmt::Debug for InternalBacktrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("InternalBacktrace") + .field("backtrace", &self.as_backtrace()) + .finish() + } +} + +fn is_backtrace_enabled<F: Fn(&str) -> Option<OsString>>(get_var: F) -> bool { + match get_var(FAILURE_BACKTRACE) { + Some(ref val) if val != "0" => true, + Some(ref val) if val == "0" => false, + _ => match get_var(GENERAL_BACKTRACE) { + Some(ref val) if val != "0" => true, + _ => false, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const YEA: Option<&str> = Some("1"); + const NAY: Option<&str> = Some("0"); + const NOT_SET: Option<&str> = None; + + macro_rules! test_enabled { + (failure: $failure:ident, general: $general:ident => $result:expr) => {{ + assert_eq!(is_backtrace_enabled(|var| match var { + FAILURE_BACKTRACE => $failure.map(OsString::from), + GENERAL_BACKTRACE => $general.map(OsString::from), + _ => panic!() + }), $result); + }} + } + + #[test] + fn always_enabled_if_failure_is_set_to_yes() { + test_enabled!(failure: YEA, general: YEA => true); + test_enabled!(failure: YEA, general: NOT_SET => true); + test_enabled!(failure: YEA, general: NAY => true); + } + + #[test] + fn never_enabled_if_failure_is_set_to_no() { + test_enabled!(failure: NAY, general: YEA => false); + test_enabled!(failure: NAY, general: NOT_SET => false); + test_enabled!(failure: NAY, general: NAY => false); + } + + #[test] + fn follows_general_if_failure_is_not_set() { + test_enabled!(failure: NOT_SET, general: YEA => true); + test_enabled!(failure: NOT_SET, general: NOT_SET => false); + test_enabled!(failure: NOT_SET, general: NAY => false); + } +} diff --git a/third_party/rust/failure/src/backtrace/mod.rs b/third_party/rust/failure/src/backtrace/mod.rs new file mode 100644 index 0000000000..9eba16d9cb --- /dev/null +++ b/third_party/rust/failure/src/backtrace/mod.rs @@ -0,0 +1,159 @@ +use core::fmt::{self, Debug, Display}; + +macro_rules! with_backtrace { ($($i:item)*) => ($(#[cfg(all(feature = "backtrace", feature = "std"))]$i)*) } +macro_rules! without_backtrace { ($($i:item)*) => ($(#[cfg(not(all(feature = "backtrace", feature = "std")))]$i)*) } + +without_backtrace! { + /// A `Backtrace`. + /// + /// This is an opaque wrapper around the backtrace provided by + /// libbacktrace. A variety of optimizations have been performed to avoid + /// unnecessary or ill-advised work: + /// + /// - If this crate is compiled in `no_std` compatible mode, `Backtrace` + /// is an empty struct, and will be completely compiled away. + /// - If this crate is run without the `RUST_BACKTRACE` environmental + /// variable enabled, the backtrace will not be generated at runtime. + /// - Even if a backtrace is generated, the most expensive part of + /// generating a backtrace is symbol resolution. This backtrace does not + /// perform symbol resolution until it is actually read (e.g. by + /// printing it). If the Backtrace is never used for anything, symbols + /// never get resolved. + /// + /// Even with these optimizations, including a backtrace in your failure + /// may not be appropriate to your use case. You are not required to put a + /// backtrace in a custom `Fail` type. + /// + /// > (We have detected that this crate was documented with no_std + /// > compatibility turned on. The version of this crate that has been + /// > documented here will never generate a backtrace.) + pub struct Backtrace { + _secret: (), + } + + impl Backtrace { + /// Constructs a new backtrace. This will only create a real backtrace + /// if the crate is compiled in std mode and the `RUST_BACKTRACE` + /// environmental variable is activated. + /// + /// > (We have detected that this crate was documented with no_std + /// > compatibility turned on. The version of this crate that has been + /// > documented here will never generate a backtrace.) + pub fn new() -> Backtrace { + Backtrace { _secret: () } + } + + #[cfg(feature = "std")] + pub(crate) fn none() -> Backtrace { + Backtrace { _secret: () } + } + + #[cfg(feature = "std")] + pub(crate) fn is_none(&self) -> bool { + true + } + + /// Returns true if displaying this backtrace would be an empty string. + /// + /// > (We have detected that this crate was documented with no_std + /// > compatibility turned on. The version of this crate that has been + /// > documented here will never generate a backtrace and this method + /// > will always return true.) + pub fn is_empty(&self) -> bool { + true + } + } + + impl Default for Backtrace { + fn default() -> Backtrace { + Backtrace::new() + } + } + + impl Debug for Backtrace { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + } + + impl Display for Backtrace { + fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + } +} + +with_backtrace! { + extern crate backtrace; + + mod internal; + + use self::internal::InternalBacktrace; + + /// A `Backtrace`. + /// + /// This is an opaque wrapper around the backtrace provided by + /// libbacktrace. A variety of optimizations have been performed to avoid + /// unnecessary or ill-advised work: + /// + /// - If this crate is compiled in `no_std` compatible mode, `Backtrace` + /// is an empty struct, and will be completely compiled away. + /// - If this crate is run without the `RUST_BACKTRACE` environmental + /// variable enabled, the backtrace will not be generated at runtime. + /// - Even if a backtrace is generated, the most expensive part of + /// generating a backtrace is symbol resolution. This backtrace does not + /// perform symbol resolution until it is actually read (e.g. by + /// printing it). If the Backtrace is never used for anything, symbols + /// never get resolved. + /// + /// Even with these optimizations, including a backtrace in your failure + /// may not be appropriate to your use case. You are not required to put a + /// backtrace in a custom `Fail` type. + pub struct Backtrace { + internal: InternalBacktrace + } + + impl Backtrace { + /// Constructs a new backtrace. This will only create a real backtrace + /// if the crate is compiled in std mode and the `RUST_BACKTRACE` + /// environmental variable is activated. + pub fn new() -> Backtrace { + Backtrace { internal: InternalBacktrace::new() } + } + + pub(crate) fn none() -> Backtrace { + Backtrace { internal: InternalBacktrace::none() } + } + + pub(crate) fn is_none(&self) -> bool { + self.internal.is_none() + } + + /// Returns true if displaying this backtrace would be an empty string. + pub fn is_empty(&self) -> bool { + self.internal.is_none() + } + } + + impl Default for Backtrace { + fn default() -> Backtrace { + Backtrace::new() + } + } + + impl Debug for Backtrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(bt) = self.internal.as_backtrace() { + Debug::fmt(bt, f) + } else { Ok(()) } + } + } + + impl Display for Backtrace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(bt) = self.internal.as_backtrace() { + Debug::fmt(bt, f) + } else { Ok(()) } + } + } +} diff --git a/third_party/rust/failure/src/box_std.rs b/third_party/rust/failure/src/box_std.rs new file mode 100644 index 0000000000..05891db13c --- /dev/null +++ b/third_party/rust/failure/src/box_std.rs @@ -0,0 +1,19 @@ +use std::error::Error; +use std::fmt; +use Fail; + +pub struct BoxStd(pub Box<dyn Error + Send + Sync + 'static>); + +impl fmt::Display for BoxStd { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +impl fmt::Debug for BoxStd { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl Fail for BoxStd {} diff --git a/third_party/rust/failure/src/compat.rs b/third_party/rust/failure/src/compat.rs new file mode 100644 index 0000000000..dec5383828 --- /dev/null +++ b/third_party/rust/failure/src/compat.rs @@ -0,0 +1,53 @@ +use core::fmt::{self, Display}; + +/// A compatibility wrapper around an error type from this crate. +/// +/// `Compat` implements `std::error::Error`, allowing the types from this +/// crate to be passed to interfaces that expect a type of that trait. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)] +pub struct Compat<E> { + pub(crate) error: E, +} + +impl<E: Display> Display for Compat<E> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.error, f) + } +} + +impl<E> Compat<E> { + /// Unwraps this into the inner error. + pub fn into_inner(self) -> E { + self.error + } + + /// Gets a reference to the inner error. + pub fn get_ref(&self) -> &E { + &self.error + } +} + +with_std! { + use std::fmt::Debug; + use std::error::Error as StdError; + + use Error; + + impl<E: Display + Debug> StdError for Compat<E> { + fn description(&self) -> &'static str { + "An error has occurred." + } + } + + impl From<Error> for Box<dyn StdError> { + fn from(error: Error) -> Box<dyn StdError> { + Box::new(Compat { error }) + } + } + + impl From<Error> for Box<dyn StdError + Send + Sync> { + fn from(error: Error) -> Box<dyn StdError + Send + Sync> { + Box::new(Compat { error }) + } + } +} diff --git a/third_party/rust/failure/src/context.rs b/third_party/rust/failure/src/context.rs new file mode 100644 index 0000000000..b5977e9a28 --- /dev/null +++ b/third_party/rust/failure/src/context.rs @@ -0,0 +1,180 @@ +use core::fmt::{self, Debug, Display}; + +use Fail; + +without_std! { + /// An error with context around it. + /// + /// The context is intended to be a human-readable, user-facing explanation for the + /// error that has occurred. The underlying error is not assumed to be end-user-relevant + /// information. + /// + /// The `Display` impl for `Context` only prints the human-readable context, while the + /// `Debug` impl also prints the underlying error. + pub struct Context<D: Display + Send + Sync + 'static> { + context: D, + } + + impl<D: Display + Send + Sync + 'static> Context<D> { + /// Creates a new context without an underlying error message. + pub fn new(context: D) -> Context<D> { + Context { context } + } + + /// Returns a reference to the context provided with this error. + pub fn get_context(&self) -> &D { + &self.context + } + + /// Maps `Context<D>` to `Context<T>` by applying a function to the contained context. + pub fn map<F, T>(self, op: F) -> Context<T> + where F: FnOnce(D) -> T, + T: Display + Send + Sync + 'static + { + Context { + context: op(self.context), + } + } + + pub(crate) fn with_err<E: Fail>(context: D, _: E) -> Context<D> { + Context { context } + } + } + + impl<D: Display + Send + Sync + 'static> Fail for Context<D> { } + + impl<D: Display + Send + Sync + 'static> Debug for Context<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.context) + } + } + + impl<D: Display + Send + Sync + 'static> Display for Context<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.context) + } + } + + #[test] + fn test_map() { + let ctx = Context::new("a string").map(|s| format!("{} with some more stuff", s)); + assert_eq!(ctx.context, String::from("a string with some more stuff")); + } +} + +with_std! { + use {Error, Backtrace}; + + /// An error with context around it. + /// + /// The context is intended to be a human-readable, user-facing explanation for the + /// error that has occurred. The underlying error is not assumed to be end-user-relevant + /// information. + /// + /// The `Display` impl for `Context` only prints the human-readable context, while the + /// `Debug` impl also prints the underlying error. + pub struct Context<D: Display + Send + Sync + 'static> { + context: D, + failure: Either<Backtrace, Error>, + } + + impl<D: Display + Send + Sync + 'static> Context<D> { + /// Creates a new context without an underlying error message. + pub fn new(context: D) -> Context<D> { + let failure = Either::This(Backtrace::new()); + Context { context, failure } + } + + /// Returns a reference to the context provided with this error. + pub fn get_context(&self) -> &D { + &self.context + } + + /// Maps `Context<D>` to `Context<T>` by applying a function to the contained context. + pub fn map<F, T>(self, op: F) -> Context<T> + where F: FnOnce(D) -> T, + T: Display + Send + Sync + 'static + { + Context { + context: op(self.context), + failure: self.failure, + } + } + + pub(crate) fn with_err<E: Into<Error>>(context: D, error: E) -> Context<D> { + let failure = Either::That(error.into()); + Context { context, failure } + } + } + + impl<D: Display + Send + Sync + 'static> Fail for Context<D> { + fn name(&self) -> Option<&str> { + self.failure.as_cause().and_then(|x| x.name()) + } + + fn cause(&self) -> Option<&dyn Fail> { + self.failure.as_cause() + } + + fn backtrace(&self) -> Option<&Backtrace> { + Some(self.failure.backtrace()) + } + } + + impl<D: Display + Send + Sync + 'static> Debug for Context<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}\n\n{}", self.failure, self.context) + } + } + + impl<D: Display + Send + Sync + 'static> Display for Context<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.context) + } + } + + enum Either<A, B> { + This(A), + That(B), + } + + impl Either<Backtrace, Error> { + fn backtrace(&self) -> &Backtrace { + match *self { + Either::This(ref backtrace) => backtrace, + Either::That(ref error) => error.backtrace(), + } + } + + fn as_cause(&self) -> Option<&dyn Fail> { + match *self { + Either::This(_) => None, + Either::That(ref error) => Some(error.as_fail()) + } + } + } + + impl Debug for Either<Backtrace, Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Either::This(ref backtrace) => write!(f, "{:?}", backtrace), + Either::That(ref error) => write!(f, "{:?}", error), + } + } + } + + #[test] + fn test_map() { + let ctx = Context::new("a string").map(|s| format!("{} with some more stuff", s)); + assert_eq!(ctx.context, String::from("a string with some more stuff")); + } +} + +impl<D> From<D> for Context<D> +where + D: Display + Send + Sync + 'static, +{ + fn from(display: D) -> Context<D> { + Context::new(display) + } +} diff --git a/third_party/rust/failure/src/error/error_impl.rs b/third_party/rust/failure/src/error/error_impl.rs new file mode 100644 index 0000000000..6a95d92d18 --- /dev/null +++ b/third_party/rust/failure/src/error/error_impl.rs @@ -0,0 +1,50 @@ +use core::any::TypeId; + +use Fail; +use backtrace::Backtrace; + +pub(crate) struct ErrorImpl { + inner: Box<Inner<dyn Fail>>, +} + +struct Inner<F: ?Sized + Fail> { + backtrace: Backtrace, + pub(crate) failure: F, +} + +impl<F: Fail> From<F> for ErrorImpl { + fn from(failure: F) -> ErrorImpl { + let inner: Inner<F> = { + let backtrace = if failure.backtrace().is_none() { + Backtrace::new() + } else { Backtrace::none() }; + Inner { failure, backtrace } + }; + ErrorImpl { inner: Box::new(inner) } + } +} + +impl ErrorImpl { + pub(crate) fn failure(&self) -> &dyn Fail { + &self.inner.failure + } + + pub(crate) fn failure_mut(&mut self) -> &mut dyn Fail { + &mut self.inner.failure + } + + pub(crate) fn backtrace(&self) -> &Backtrace { + &self.inner.backtrace + } + + pub(crate) fn downcast<T: Fail>(self) -> Result<T, ErrorImpl> { + if self.failure().__private_get_type_id__() == TypeId::of::<T>() { + let ErrorImpl { inner } = self; + let casted = unsafe { Box::from_raw(Box::into_raw(inner) as *mut Inner<T>) }; + let Inner { backtrace:_, failure } = *casted; + Ok(failure) + } else { + Err(self) + } + } +} diff --git a/third_party/rust/failure/src/error/error_impl_small.rs b/third_party/rust/failure/src/error/error_impl_small.rs new file mode 100644 index 0000000000..6ff7c78ec7 --- /dev/null +++ b/third_party/rust/failure/src/error/error_impl_small.rs @@ -0,0 +1,132 @@ +use std::heap::{Heap, Alloc, Layout}; + +use core::mem; +use core::ptr; + +use Fail; +use backtrace::Backtrace; + +pub(crate) struct ErrorImpl { + inner: &'static mut Inner, +} + +// Dynamically sized inner value +struct Inner { + backtrace: Backtrace, + vtable: *const VTable, + failure: FailData, +} + +unsafe impl Send for Inner { } +unsafe impl Sync for Inner { } + +extern { + type VTable; + type FailData; +} + +#[allow(dead_code)] +struct InnerRaw<F> { + header: InnerHeader, + failure: F, +} + +#[allow(dead_code)] +struct InnerHeader { + backtrace: Backtrace, + vtable: *const VTable, +} + +struct TraitObject { + #[allow(dead_code)] + data: *const FailData, + vtable: *const VTable, +} + +impl<F: Fail> From<F> for ErrorImpl { + fn from(failure: F) -> ErrorImpl { + let backtrace = if failure.backtrace().is_none() { + Backtrace::new() + } else { + Backtrace::none() + }; + + unsafe { + let vtable = mem::transmute::<_, TraitObject>(&failure as &Fail).vtable; + + let ptr: *mut InnerRaw<F> = match Heap.alloc(Layout::new::<InnerRaw<F>>()) { + Ok(p) => p as *mut InnerRaw<F>, + Err(e) => Heap.oom(e), + }; + + // N.B. must use `ptr::write`, not `=`, to avoid dropping the contents of `*ptr` + ptr::write(ptr, InnerRaw { + header: InnerHeader { + backtrace, + vtable, + }, + failure, + }); + + let inner: &'static mut Inner = mem::transmute(ptr); + + ErrorImpl { inner } + } + } +} + +impl ErrorImpl { + pub(crate) fn failure(&self) -> &Fail { + unsafe { + mem::transmute::<TraitObject, &Fail>(TraitObject { + data: &self.inner.failure as *const FailData, + vtable: self.inner.vtable, + }) + } + } + + pub(crate) fn failure_mut(&mut self) -> &mut Fail { + unsafe { + mem::transmute::<TraitObject, &mut Fail>(TraitObject { + data: &mut self.inner.failure as *const FailData, + vtable: self.inner.vtable, + }) + } + } + + pub(crate) fn backtrace(&self) -> &Backtrace { + &self.inner.backtrace + } + + pub(crate) fn downcast<T: Fail>(self) -> Result<T, ErrorImpl> { + let ret: Option<T> = self.failure().downcast_ref().map(|fail| { + unsafe { + // drop the backtrace + let _ = ptr::read(&self.inner.backtrace as *const Backtrace); + // read out the fail type + ptr::read(fail as *const T) + } + }); + match ret { + Some(ret) => { + // forget self (backtrace is dropped, failure is moved + mem::forget(self); + Ok(ret) + } + _ => Err(self) + } + } +} + + +#[cfg(test)] +mod test { + use std::mem::size_of; + + use super::ErrorImpl; + + #[test] + fn assert_is_one_word() { + assert_eq!(size_of::<ErrorImpl>(), size_of::<usize>()); + } +} diff --git a/third_party/rust/failure/src/error/mod.rs b/third_party/rust/failure/src/error/mod.rs new file mode 100644 index 0000000000..842dbbae0c --- /dev/null +++ b/third_party/rust/failure/src/error/mod.rs @@ -0,0 +1,248 @@ +use core::fmt::{self, Display, Debug}; + +use {Causes, Fail}; +use backtrace::Backtrace; +use context::Context; +use compat::Compat; + +#[cfg(feature = "std")] +use box_std::BoxStd; + +#[cfg_attr(feature = "small-error", path = "./error_impl_small.rs")] +mod error_impl; +use self::error_impl::ErrorImpl; + +#[cfg(feature = "std")] +use std::error::Error as StdError; + + +/// The `Error` type, which can contain any failure. +/// +/// Functions which accumulate many kinds of errors should return this type. +/// All failures can be converted into it, so functions which catch those +/// errors can be tried with `?` inside of a function that returns this kind +/// of error. +/// +/// In addition to implementing `Debug` and `Display`, this type carries `Backtrace` +/// information, and can be downcast into the failure that underlies it for +/// more detailed inspection. +pub struct Error { + imp: ErrorImpl, +} + +impl<F: Fail> From<F> for Error { + fn from(failure: F) -> Error { + Error { + imp: ErrorImpl::from(failure) + } + } +} + +impl Error { + /// Creates an `Error` from `Box<std::error::Error>`. + /// + /// This method is useful for comparability with code, + /// which does not use the `Fail` trait. + /// + /// # Example + /// + /// ``` + /// use std::error::Error as StdError; + /// use failure::Error; + /// + /// fn app_fn() -> Result<i32, Error> { + /// let x = library_fn().map_err(Error::from_boxed_compat)?; + /// Ok(x * 2) + /// } + /// + /// fn library_fn() -> Result<i32, Box<StdError + Sync + Send + 'static>> { + /// Ok(92) + /// } + /// ``` + #[cfg(feature = "std")] + pub fn from_boxed_compat(err: Box<dyn StdError + Sync + Send + 'static>) -> Error { + Error::from(BoxStd(err)) + } + + /// Return a reference to the underlying failure that this `Error` + /// contains. + pub fn as_fail(&self) -> &dyn Fail { + self.imp.failure() + } + + /// Returns the name of the underlying fail. + pub fn name(&self) -> Option<&str> { + self.as_fail().name() + } + + /// Returns a reference to the underlying cause of this `Error`. Unlike the + /// method on `Fail`, this does not return an `Option`. The `Error` type + /// always has an underlying failure. + /// + /// This method has been deprecated in favor of the [Error::as_fail] method, + /// which does the same thing. + #[deprecated(since = "0.1.2", note = "please use 'as_fail()' method instead")] + pub fn cause(&self) -> &dyn Fail { + self.as_fail() + } + + /// Gets a reference to the `Backtrace` for this `Error`. + /// + /// If the failure this wrapped carried a backtrace, that backtrace will + /// be returned. Otherwise, the backtrace will have been constructed at + /// the point that failure was cast into the `Error` type. + pub fn backtrace(&self) -> &Backtrace { + self.imp.failure().backtrace().unwrap_or(&self.imp.backtrace()) + } + + /// Provides context for this `Error`. + /// + /// This can provide additional information about this error, appropriate + /// to the semantics of the current layer. That is, if you have a + /// lower-level error, such as an IO error, you can provide additional context + /// about what that error means in the context of your function. This + /// gives users of this function more information about what has gone + /// wrong. + /// + /// This takes any type that implements `Display`, as well as + /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String` + /// or a string literal, or a failure, or some other custom context-carrying + /// type. + pub fn context<D: Display + Send + Sync + 'static>(self, context: D) -> Context<D> { + Context::with_err(context, self) + } + + /// Wraps `Error` in a compatibility type. + /// + /// This type implements the `Error` trait from `std::error`. If you need + /// to pass failure's `Error` to an interface that takes any `Error`, you + /// can use this method to get a compatible type. + pub fn compat(self) -> Compat<Error> { + Compat { error: self } + } + + /// Attempts to downcast this `Error` to a particular `Fail` type. + /// + /// This downcasts by value, returning an owned `T` if the underlying + /// failure is of the type `T`. For this reason it returns a `Result` - in + /// the case that the underlying error is of a different type, the + /// original `Error` is returned. + pub fn downcast<T: Fail>(self) -> Result<T, Error> { + self.imp.downcast().map_err(|imp| Error { imp }) + } + + /// Returns the "root cause" of this error - the last value in the + /// cause chain which does not return an underlying `cause`. + pub fn find_root_cause(&self) -> &dyn Fail { + self.as_fail().find_root_cause() + } + + /// Returns a iterator over the causes of this error with the cause + /// of the fail as the first item and the `root_cause` as the final item. + /// + /// Use `iter_chain` to also include the fail of this error itself. + pub fn iter_causes(&self) -> Causes { + self.as_fail().iter_causes() + } + + /// Returns a iterator over all fails up the chain from the current + /// as the first item up to the `root_cause` as the final item. + /// + /// This means that the chain also includes the fail itself which + /// means that it does *not* start with `cause`. To skip the outermost + /// fail use `iter_causes` instead. + pub fn iter_chain(&self) -> Causes { + self.as_fail().iter_chain() + } + + /// Attempts to downcast this `Error` to a particular `Fail` type by + /// reference. + /// + /// If the underlying error is not of type `T`, this will return `None`. + pub fn downcast_ref<T: Fail>(&self) -> Option<&T> { + self.imp.failure().downcast_ref() + } + + /// Attempts to downcast this `Error` to a particular `Fail` type by + /// mutable reference. + /// + /// If the underlying error is not of type `T`, this will return `None`. + pub fn downcast_mut<T: Fail>(&mut self) -> Option<&mut T> { + self.imp.failure_mut().downcast_mut() + } + + /// Deprecated alias to `find_root_cause`. + #[deprecated(since = "0.1.2", note = "please use the 'find_root_cause()' method instead")] + pub fn root_cause(&self) -> &dyn Fail { + ::find_root_cause(self.as_fail()) + } + + /// Deprecated alias to `iter_causes`. + #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")] + pub fn causes(&self) -> Causes { + Causes { fail: Some(self.as_fail()) } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.imp.failure(), f) + } +} + +impl Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let backtrace = self.imp.backtrace(); + if backtrace.is_none() { + Debug::fmt(&self.imp.failure(), f) + } else { + write!(f, "{:?}\n\n{:?}", &self.imp.failure(), backtrace) + } + } +} + +impl AsRef<dyn Fail> for Error { + fn as_ref(&self) -> &dyn Fail { + self.as_fail() + } +} + +#[cfg(test)] +mod test { + use std::io; + use super::Error; + + fn assert_just_data<T: Send + Sync + 'static>() { } + + #[test] + fn assert_error_is_just_data() { + assert_just_data::<Error>(); + } + + #[test] + fn methods_seem_to_work() { + let io_error: io::Error = io::Error::new(io::ErrorKind::NotFound, "test"); + let error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into(); + assert!(error.downcast_ref::<io::Error>().is_some()); + let _: ::Backtrace = *error.backtrace(); + assert_eq!(format!("{:?}", io_error), format!("{:?}", error)); + assert_eq!(format!("{}", io_error), format!("{}", error)); + drop(error); + assert!(true); + } + + #[test] + fn downcast_can_be_used() { + let mut error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into(); + { + let real_io_error_ref = error.downcast_ref::<io::Error>().unwrap(); + assert_eq!(real_io_error_ref.to_string(), "test"); + } + { + let real_io_error_mut = error.downcast_mut::<io::Error>().unwrap(); + assert_eq!(real_io_error_mut.to_string(), "test"); + } + let real_io_error = error.downcast::<io::Error>().unwrap(); + assert_eq!(real_io_error.to_string(), "test"); + } +} diff --git a/third_party/rust/failure/src/error_message.rs b/third_party/rust/failure/src/error_message.rs new file mode 100644 index 0000000000..560d317b4d --- /dev/null +++ b/third_party/rust/failure/src/error_message.rs @@ -0,0 +1,32 @@ +use core::fmt::{self, Display, Debug}; + +use Fail; +use Error; + +/// Constructs a `Fail` type from a string. +/// +/// This is a convenient way to turn a string into an error value that +/// can be passed around, if you do not want to create a new `Fail` type for +/// this use case. +pub fn err_msg<D: Display + Debug + Sync + Send + 'static>(msg: D) -> Error { + Error::from(ErrorMessage { msg }) +} + +/// A `Fail` type that just contains an error message. You can construct +/// this from the `err_msg` function. +#[derive(Debug)] +struct ErrorMessage<D: Display + Debug + Sync + Send + 'static> { + msg: D, +} + +impl<D: Display + Debug + Sync + Send + 'static> Fail for ErrorMessage<D> { + fn name(&self) -> Option<&str> { + Some("failure::ErrorMessage") + } +} + +impl<D: Display + Debug + Sync + Send + 'static> Display for ErrorMessage<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.msg, f) + } +} diff --git a/third_party/rust/failure/src/lib.rs b/third_party/rust/failure/src/lib.rs new file mode 100644 index 0000000000..41a45ba474 --- /dev/null +++ b/third_party/rust/failure/src/lib.rs @@ -0,0 +1,307 @@ +//! An experimental new error-handling library. Guide-style introduction +//! is available [here](https://boats.gitlab.io/failure/). +//! +//! The primary items exported by this library are: +//! +//! - `Fail`: a new trait for custom error types in Rust. +//! - `Error`: a wrapper around `Fail` types to make it easy to coalesce them +//! at higher levels. +//! +//! As a general rule, library authors should create their own error types and +//! implement `Fail` for them, whereas application authors should primarily +//! deal with the `Error` type. There are exceptions to this rule, though, in +//! both directions, and users should do whatever seems most appropriate to +//! their situation. +//! +//! ## Backtraces +//! +//! Backtraces are disabled by default. To turn backtraces on, enable +//! the `backtrace` Cargo feature and set the `RUST_BACKTRACE` environment +//! variable to a non-zero value (this also enables backtraces for panics). +//! Use the `RUST_FAILURE_BACKTRACE` variable to enable or disable backtraces +//! for `failure` specifically. +#![cfg_attr(not(feature = "std"), no_std)] +#![deny(missing_docs)] +#![deny(warnings)] +#![cfg_attr(feature = "small-error", feature(extern_types, allocator_api))] + +macro_rules! with_std { ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) } +macro_rules! without_std { ($($i:item)*) => ($(#[cfg(not(feature = "std"))]$i)*) } + +// Re-export libcore using an alias so that the macros can work without +// requiring `extern crate core` downstream. +#[doc(hidden)] +pub extern crate core as _core; + +mod as_fail; +mod backtrace; +#[cfg(feature = "std")] +mod box_std; +mod compat; +mod context; +mod result_ext; + +use core::any::TypeId; +use core::fmt::{Debug, Display}; + +pub use as_fail::AsFail; +pub use backtrace::Backtrace; +pub use compat::Compat; +pub use context::Context; +pub use result_ext::ResultExt; + +#[cfg(feature = "failure_derive")] +#[allow(unused_imports)] +#[macro_use] +extern crate failure_derive; + +#[cfg(feature = "failure_derive")] +#[doc(hidden)] +pub use failure_derive::*; + +with_std! { + extern crate core; + + mod sync_failure; + pub use sync_failure::SyncFailure; + + mod error; + + use std::error::Error as StdError; + + pub use error::Error; + + /// A common result with an `Error`. + pub type Fallible<T> = Result<T, Error>; + + mod macros; + mod error_message; + pub use error_message::err_msg; +} + +/// The `Fail` trait. +/// +/// Implementors of this trait are called 'failures'. +/// +/// All error types should implement `Fail`, which provides a baseline of +/// functionality that they all share. +/// +/// `Fail` has no required methods, but it does require that your type +/// implement several other traits: +/// +/// - `Display`: to print a user-friendly representation of the error. +/// - `Debug`: to print a verbose, developer-focused representation of the +/// error. +/// - `Send + Sync`: Your error type is required to be safe to transfer to and +/// reference from another thread +/// +/// Additionally, all failures must be `'static`. This enables downcasting. +/// +/// `Fail` provides several methods with default implementations. Two of these +/// may be appropriate to override depending on the definition of your +/// particular failure: the `cause` and `backtrace` methods. +/// +/// The `failure_derive` crate provides a way to derive the `Fail` trait for +/// your type. Additionally, all types that already implement +/// `std::error::Error`, and are also `Send`, `Sync`, and `'static`, implement +/// `Fail` by a blanket impl. +pub trait Fail: Display + Debug + Send + Sync + 'static { + /// Returns the "name" of the error. + /// + /// This is typically the type name. Not all errors will implement + /// this. This method is expected to be most useful in situations + /// where errors need to be reported to external instrumentation systems + /// such as crash reporters. + fn name(&self) -> Option<&str> { + None + } + + /// Returns a reference to the underlying cause of this failure, if it + /// is an error that wraps other errors. + /// + /// Returns `None` if this failure does not have another error as its + /// underlying cause. By default, this returns `None`. + /// + /// This should **never** return a reference to `self`, but only return + /// `Some` when it can return a **different** failure. Users may loop + /// over the cause chain, and returning `self` would result in an infinite + /// loop. + fn cause(&self) -> Option<&dyn Fail> { + None + } + + /// Returns a reference to the `Backtrace` carried by this failure, if it + /// carries one. + /// + /// Returns `None` if this failure does not carry a backtrace. By + /// default, this returns `None`. + fn backtrace(&self) -> Option<&Backtrace> { + None + } + + /// Provides context for this failure. + /// + /// This can provide additional information about this error, appropriate + /// to the semantics of the current layer. That is, if you have a + /// lower-level error, such as an IO error, you can provide additional context + /// about what that error means in the context of your function. This + /// gives users of this function more information about what has gone + /// wrong. + /// + /// This takes any type that implements `Display`, as well as + /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String` + /// or a string literal, or another failure, or some other custom context-carrying + /// type. + fn context<D>(self, context: D) -> Context<D> + where + D: Display + Send + Sync + 'static, + Self: Sized, + { + Context::with_err(context, self) + } + + /// Wraps this failure in a compatibility wrapper that implements + /// `std::error::Error`. + /// + /// This allows failures to be compatible with older crates that + /// expect types that implement the `Error` trait from `std::error`. + fn compat(self) -> Compat<Self> + where + Self: Sized, + { + Compat { error: self } + } + + #[doc(hidden)] + #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")] + fn causes(&self) -> Causes + where + Self: Sized, + { + Causes { fail: Some(self) } + } + + #[doc(hidden)] + #[deprecated( + since = "0.1.2", + note = "please use the 'find_root_cause()' method instead" + )] + fn root_cause(&self) -> &dyn Fail + where + Self: Sized, + { + find_root_cause(self) + } + + #[doc(hidden)] + fn __private_get_type_id__(&self) -> TypeId { + TypeId::of::<Self>() + } +} + +impl dyn Fail { + /// Attempts to downcast this failure to a concrete type by reference. + /// + /// If the underlying error is not of type `T`, this will return `None`. + pub fn downcast_ref<T: Fail>(&self) -> Option<&T> { + if self.__private_get_type_id__() == TypeId::of::<T>() { + unsafe { Some(&*(self as *const dyn Fail as *const T)) } + } else { + None + } + } + + /// Attempts to downcast this failure to a concrete type by mutable + /// reference. + /// + /// If the underlying error is not of type `T`, this will return `None`. + pub fn downcast_mut<T: Fail>(&mut self) -> Option<&mut T> { + if self.__private_get_type_id__() == TypeId::of::<T>() { + unsafe { Some(&mut *(self as *mut dyn Fail as *mut T)) } + } else { + None + } + } + + /// Returns the "root cause" of this `Fail` - the last value in the + /// cause chain which does not return an underlying `cause`. + /// + /// If this type does not have a cause, `self` is returned, because + /// it is its own root cause. + /// + /// This is equivalent to iterating over `iter_causes()` and taking + /// the last item. + pub fn find_root_cause(&self) -> &dyn Fail { + find_root_cause(self) + } + + /// Returns a iterator over the causes of this `Fail` with the cause + /// of this fail as the first item and the `root_cause` as the final item. + /// + /// Use `iter_chain` to also include the fail itself. + pub fn iter_causes(&self) -> Causes { + Causes { fail: self.cause() } + } + + /// Returns a iterator over all fails up the chain from the current + /// as the first item up to the `root_cause` as the final item. + /// + /// This means that the chain also includes the fail itself which + /// means that it does *not* start with `cause`. To skip the outermost + /// fail use `iter_causes` instead. + pub fn iter_chain(&self) -> Causes { + Causes { fail: Some(self) } + } + + /// Deprecated alias to `find_root_cause`. + #[deprecated( + since = "0.1.2", + note = "please use the 'find_root_cause()' method instead" + )] + pub fn root_cause(&self) -> &dyn Fail { + find_root_cause(self) + } + + /// Deprecated alias to `iter_chain`. + #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")] + pub fn causes(&self) -> Causes { + Causes { fail: Some(self) } + } +} + +#[cfg(feature = "std")] +impl<E: StdError + Send + Sync + 'static> Fail for E {} + +#[cfg(feature = "std")] +impl Fail for Box<dyn Fail> { + fn cause(&self) -> Option<&dyn Fail> { + (**self).cause() + } + + fn backtrace(&self) -> Option<&Backtrace> { + (**self).backtrace() + } +} + +/// A iterator over the causes of a `Fail` +pub struct Causes<'f> { + fail: Option<&'f dyn Fail>, +} + +impl<'f> Iterator for Causes<'f> { + type Item = &'f dyn Fail; + fn next(&mut self) -> Option<&'f dyn Fail> { + self.fail.map(|fail| { + self.fail = fail.cause(); + fail + }) + } +} + +fn find_root_cause(mut fail: &dyn Fail) -> &dyn Fail { + while let Some(cause) = fail.cause() { + fail = cause; + } + + fail +} diff --git a/third_party/rust/failure/src/macros.rs b/third_party/rust/failure/src/macros.rs new file mode 100644 index 0000000000..c0a9dad294 --- /dev/null +++ b/third_party/rust/failure/src/macros.rs @@ -0,0 +1,64 @@ +/// Exits a function early with an `Error`. +/// +/// The `bail!` macro provides an easy way to exit a function. `bail!(X)` is +/// equivalent to writing: +/// +/// ```rust,ignore +/// return Err(format_err!(X)) +/// ``` +#[macro_export] +macro_rules! bail { + ($e:expr) => { + return Err($crate::err_msg($e)); + }; + ($fmt:expr, $($arg:tt)*) => { + return Err($crate::err_msg(format!($fmt, $($arg)*))); + }; +} + +/// Exits a function early with an `Error` if the condition is not satisfied. +/// +/// Similar to `assert!`, `ensure!` takes a condition and exits the function +/// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`, +/// it does not panic. +#[macro_export(local_inner_macros)] +macro_rules! ensure { + ($cond:expr) => { + if !($cond) { + bail!("{}", _failure__stringify!($cond)); + } + }; + ($cond:expr, $e:expr) => { + if !($cond) { + bail!($e); + } + }; + ($cond:expr, $fmt:expr, $($arg:tt)*) => { + if !($cond) { + bail!($fmt, $($arg)*); + } + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! _failure__stringify { + ($($inner:tt)*) => { + stringify! { $($inner)* } + } +} + +/// Constructs an `Error` using the standard string interpolation syntax. +/// +/// ```rust +/// #[macro_use] extern crate failure; +/// +/// fn main() { +/// let code = 101; +/// let err = format_err!("Error code: {}", code); +/// } +/// ``` +#[macro_export] +macro_rules! format_err { + ($($arg:tt)*) => { $crate::err_msg(format!($($arg)*)) } +} diff --git a/third_party/rust/failure/src/result_ext.rs b/third_party/rust/failure/src/result_ext.rs new file mode 100644 index 0000000000..f4125cdd68 --- /dev/null +++ b/third_party/rust/failure/src/result_ext.rs @@ -0,0 +1,203 @@ +use core::fmt::Display; + +use {Compat, Context, Fail}; + +/// Extension methods for `Result`. +pub trait ResultExt<T, E> { + /// Wraps the error in `Compat` to make it compatible with older error + /// handling APIs that expect `std::error::Error`. + /// + /// # Examples + /// + /// ``` + /// # fn main() { + /// # tests::run_test(); + /// # } + /// # + /// # #[cfg(not(all(feature = "std", feature = "derive")))] mod tests { pub fn run_test() { } } + /// # + /// # #[cfg(all(feature = "std", feature = "derive"))] mod tests { + /// use std::error::Error; + /// # use std::fmt; + /// # + /// # extern crate failure; + /// # + /// # use tests::failure::ResultExt; + /// # + /// # #[derive(Debug)] + /// struct CustomError; + /// + /// impl Error for CustomError { + /// fn description(&self) -> &str { + /// "My custom error message" + /// } + /// + /// fn cause(&self) -> Option<&Error> { + /// None + /// } + /// } + /// # + /// # impl fmt::Display for CustomError { + /// # fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// # write!(f, "{}", self.description()) + /// # } + /// # } + /// # + /// # pub fn run_test() { + /// + /// let x = (|| -> Result<(), failure::Error> { + /// Err(CustomError).compat()? + /// })().with_context(|e| { + /// format!("An error occured: {}", e) + /// }).unwrap_err(); + /// + /// let x = format!("{}", x); + /// + /// assert_eq!(x, "An error occured: My custom error message"); + /// # } + /// + /// # } + /// ``` + fn compat(self) -> Result<T, Compat<E>>; + + /// Wraps the error type in a context type. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "std", feature = "derive"))] + /// # #[macro_use] extern crate failure; + /// # + /// # #[cfg(all(feature = "std", feature = "derive"))] + /// # #[macro_use] extern crate failure_derive; + /// # + /// # fn main() { + /// # tests::run_test(); + /// # } + /// # + /// # #[cfg(not(all(feature = "std", feature = "derive")))] mod tests { pub fn run_test() { } } + /// # + /// # #[cfg(all(feature = "std", feature = "derive"))] mod tests { + /// # + /// # use failure::{self, ResultExt}; + /// # + /// #[derive(Fail, Debug)] + /// #[fail(display = "")] + /// struct CustomError; + /// # + /// # pub fn run_test() { + /// + /// let x = (|| -> Result<(), failure::Error> { + /// Err(CustomError)? + /// })().context(format!("An error occured")).unwrap_err(); + /// + /// let x = format!("{}", x); + /// + /// assert_eq!(x, "An error occured"); + /// # } + /// + /// # } + /// ``` + fn context<D>(self, context: D) -> Result<T, Context<D>> + where + D: Display + Send + Sync + 'static; + + /// Wraps the error type in a context type generated by looking at the + /// error value. + /// + /// # Examples + /// + /// ``` + /// # #[cfg(all(feature = "std", feature = "derive"))] + /// # #[macro_use] extern crate failure; + /// # + /// # #[cfg(all(feature = "std", feature = "derive"))] + /// # #[macro_use] extern crate failure_derive; + /// # + /// # fn main() { + /// # tests::run_test(); + /// # } + /// # + /// # #[cfg(not(all(feature = "std", feature = "derive")))] mod tests { pub fn run_test() { } } + /// # + /// # #[cfg(all(feature = "std", feature = "derive"))] mod tests { + /// # + /// # use failure::{self, ResultExt}; + /// # + /// #[derive(Fail, Debug)] + /// #[fail(display = "My custom error message")] + /// struct CustomError; + /// # + /// # pub fn run_test() { + /// + /// let x = (|| -> Result<(), failure::Error> { + /// Err(CustomError)? + /// })().with_context(|e| { + /// format!("An error occured: {}", e) + /// }).unwrap_err(); + /// + /// let x = format!("{}", x); + /// + /// assert_eq!(x, "An error occured: My custom error message"); + /// # } + /// + /// # } + /// ``` + fn with_context<F, D>(self, f: F) -> Result<T, Context<D>> + where + F: FnOnce(&E) -> D, + D: Display + Send + Sync + 'static; +} + +impl<T, E> ResultExt<T, E> for Result<T, E> +where + E: Fail, +{ + fn compat(self) -> Result<T, Compat<E>> { + self.map_err(|err| err.compat()) + } + + fn context<D>(self, context: D) -> Result<T, Context<D>> + where + D: Display + Send + Sync + 'static, + { + self.map_err(|failure| failure.context(context)) + } + + fn with_context<F, D>(self, f: F) -> Result<T, Context<D>> + where + F: FnOnce(&E) -> D, + D: Display + Send + Sync + 'static, + { + self.map_err(|failure| { + let context = f(&failure); + failure.context(context) + }) + } +} + +with_std! { + use Error; + + impl<T> ResultExt<T, Error> for Result<T, Error> { + fn compat(self) -> Result<T, Compat<Error>> { + self.map_err(|err| err.compat()) + } + + fn context<D>(self, context: D) -> Result<T, Context<D>> where + D: Display + Send + Sync + 'static + { + self.map_err(|failure| failure.context(context)) + } + + fn with_context<F, D>(self, f: F) -> Result<T, Context<D>> where + F: FnOnce(&Error) -> D, + D: Display + Send + Sync + 'static + { + self.map_err(|failure| { + let context = f(&failure); + failure.context(context) + }) + } + } +} diff --git a/third_party/rust/failure/src/small_error.rs b/third_party/rust/failure/src/small_error.rs new file mode 100644 index 0000000000..09646e3915 --- /dev/null +++ b/third_party/rust/failure/src/small_error.rs @@ -0,0 +1,264 @@ +use core::fmt::{self, Display, Debug}; +use std::heap::{Heap, Alloc, Layout}; + +use core::mem; +use core::ptr; + +use {Causes, Fail}; +use backtrace::Backtrace; +use context::Context; +use compat::Compat; + +/// The `Error` type, which can contain any failure. +/// +/// Functions which accumulate many kinds of errors should return this type. +/// All failures can be converted into it, so functions which catch those +/// errors can be tried with `?` inside of a function that returns this kind +/// of error. +/// +/// In addition to implementing `Debug` and `Display`, this type carries `Backtrace` +/// information, and can be downcast into the failure that underlies it for +/// more detailed inspection. +pub struct Error { + inner: &'static mut Inner, +} + +// Dynamically sized inner value +struct Inner { + backtrace: Backtrace, + vtable: *const VTable, + failure: FailData, +} + +unsafe impl Send for Inner { } +unsafe impl Sync for Inner { } + +extern { + type VTable; + type FailData; +} + +struct InnerRaw<F> { + header: InnerHeader, + failure: F, +} + +struct InnerHeader { + backtrace: Backtrace, + vtable: *const VTable, +} + +struct TraitObject { + #[allow(dead_code)] + data: *const FailData, + vtable: *const VTable, +} + +impl<F: Fail> From<F> for Error { + fn from(failure: F) -> Error { + let backtrace = if failure.backtrace().is_none() { + Backtrace::new() + } else { + Backtrace::none() + }; + + unsafe { + let vtable = mem::transmute::<_, TraitObject>(&failure as &Fail).vtable; + + let ptr: *mut InnerRaw<F> = match Heap.alloc(Layout::new::<InnerRaw<F>>()) { + Ok(p) => p as *mut InnerRaw<F>, + Err(e) => Heap.oom(e), + }; + + // N.B. must use `ptr::write`, not `=`, to avoid dropping the contents of `*ptr` + ptr::write(ptr, InnerRaw { + header: InnerHeader { + backtrace, + vtable, + }, + failure, + }); + + let inner: &'static mut Inner = mem::transmute(ptr); + + Error { inner } + } + } +} + +impl Inner { + fn failure(&self) -> &Fail { + unsafe { + mem::transmute::<TraitObject, &Fail>(TraitObject { + data: &self.failure as *const FailData, + vtable: self.vtable, + }) + } + } + + fn failure_mut(&mut self) -> &mut Fail { + unsafe { + mem::transmute::<TraitObject, &mut Fail>(TraitObject { + data: &mut self.failure as *const FailData, + vtable: self.vtable, + }) + } + } +} + +impl Error { + /// Returns a reference to the underlying cause of this `Error`. Unlike the + /// method on `Fail`, this does not return an `Option`. The `Error` type + /// always has an underlying failure. + pub fn cause(&self) -> &Fail { + self.inner.failure() + } + + /// Gets a reference to the `Backtrace` for this `Error`. + /// + /// If the failure this wrapped carried a backtrace, that backtrace will + /// be returned. Otherwise, the backtrace will have been constructed at + /// the point that failure was cast into the `Error` type. + pub fn backtrace(&self) -> &Backtrace { + self.inner.failure().backtrace().unwrap_or(&self.inner.backtrace) + } + + /// Provides context for this `Error`. + /// + /// This can provide additional information about this error, appropriate + /// to the semantics of the current layer. That is, if you have a + /// lower-level error, such as an IO error, you can provide additional context + /// about what that error means in the context of your function. This + /// gives users of this function more information about what has gone + /// wrong. + /// + /// This takes any type that implements `Display`, as well as + /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String` + /// or a string literal, or a failure, or some other custom context-carrying + /// type. + pub fn context<D: Display + Send + Sync + 'static>(self, context: D) -> Context<D> { + Context::with_err(context, self) + } + + /// Wraps `Error` in a compatibility type. + /// + /// This type implements the `Error` trait from `std::error`. If you need + /// to pass failure's `Error` to an interface that takes any `Error`, you + /// can use this method to get a compatible type. + pub fn compat(self) -> Compat<Error> { + Compat { error: self } + } + + /// Attempts to downcast this `Error` to a particular `Fail` type. + /// + /// This downcasts by value, returning an owned `T` if the underlying + /// failure is of the type `T`. For this reason it returns a `Result` - in + /// the case that the underlying error is of a different type, the + /// original `Error` is returned. + pub fn downcast<T: Fail>(self) -> Result<T, Error> { + let ret: Option<T> = self.downcast_ref().map(|fail| { + unsafe { + // drop the backtrace + let _ = ptr::read(&self.inner.backtrace as *const Backtrace); + // read out the fail type + ptr::read(fail as *const T) + } + }); + match ret { + Some(ret) => { + // forget self (backtrace is dropped, failure is moved + mem::forget(self); + Ok(ret) + } + _ => Err(self) + } + } + + /// Returns the "root cause" of this error - the last value in the + /// cause chain which does not return an underlying `cause`. + pub fn root_cause(&self) -> &Fail { + ::find_root_cause(self.cause()) + } + + /// Attempts to downcast this `Error` to a particular `Fail` type by + /// reference. + /// + /// If the underlying error is not of type `T`, this will return `None`. + pub fn downcast_ref<T: Fail>(&self) -> Option<&T> { + self.inner.failure().downcast_ref() + } + + /// Attempts to downcast this `Error` to a particular `Fail` type by + /// mutable reference. + /// + /// If the underlying error is not of type `T`, this will return `None`. + pub fn downcast_mut<T: Fail>(&mut self) -> Option<&mut T> { + self.inner.failure_mut().downcast_mut() + } + + /// Returns a iterator over the causes of the `Error`, beginning with + /// the failure returned by the `cause` method and ending with the failure + /// returned by `root_cause`. + pub fn causes(&self) -> Causes { + Causes { fail: Some(self.cause()) } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(self.inner.failure(), f) + } +} + +impl Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.inner.backtrace.is_none() { + Debug::fmt(self.inner.failure(), f) + } else { + write!(f, "{:?}\n\n{:?}", self.inner.failure(), self.inner.backtrace) + } + } +} + +impl Drop for Error { + fn drop(&mut self) { + unsafe { + let layout = { + let header = Layout::new::<InnerHeader>(); + header.extend(Layout::for_value(self.inner.failure())).unwrap().0 + }; + Heap.dealloc(self.inner as *const _ as *const u8 as *mut u8, layout); + } + } +} + +#[cfg(test)] +mod test { + use std::mem::size_of; + use std::io; + + use super::Error; + + #[test] + fn assert_error_is_just_data() { + fn assert_just_data<T: Send + Sync + 'static>() { } + assert_just_data::<Error>(); + } + + #[test] + fn assert_is_one_word() { + assert_eq!(size_of::<Error>(), size_of::<usize>()); + } + + #[test] + fn methods_seem_to_work() { + let io_error: io::Error = io::Error::new(io::ErrorKind::NotFound, "test"); + let error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into(); + assert!(error.downcast_ref::<io::Error>().is_some()); + let _: ::Backtrace = *error.backtrace(); + assert_eq!(format!("{:?}", io_error), format!("{:?}", error)); + assert_eq!(format!("{}", io_error), format!("{}", error)); + drop(error); + assert!(true); + } +} diff --git a/third_party/rust/failure/src/sync_failure.rs b/third_party/rust/failure/src/sync_failure.rs new file mode 100644 index 0000000000..63e966cdd5 --- /dev/null +++ b/third_party/rust/failure/src/sync_failure.rs @@ -0,0 +1,97 @@ +use Fail; +use std::error::Error; +use std::fmt::{self, Debug, Display}; +use std::sync::Mutex; + +/// Wrapper for `std` errors to make them `Sync`. +/// +/// This exists to coerce existing types that are only `Error + Send + +/// 'static` into a `Fail`-compatible representation, most notably for +/// types generated by `error-chain`. +/// +/// Unfortunately, this requires wrapping the error in a `Mutex`, which must +/// be locked for every `Debug`/`Display`. Therefore, this should be +/// something of a last resort in making the error work with `failure`. +/// +pub struct SyncFailure<T> { + inner: Mutex<T>, +} + +impl<E: Error + Send + 'static> SyncFailure<E> { + /// Wraps a non-`Sync` `Error` in order to make it implement `Fail`. + /// + /// # Example + /// + /// ```rust + /// extern crate failure; + /// + /// # use std::error::Error as StdError; + /// # use std::fmt::{self, Display}; + /// use failure::{Error, SyncFailure}; + /// use std::cell::RefCell; + /// + /// #[derive(Debug)] + /// struct NonSyncError { + /// // RefCells are non-Sync, so structs containing them will be + /// // non-Sync as well. + /// count: RefCell<usize>, + /// } + /// + /// // implement Display/Error for NonSyncError... + /// # + /// # impl StdError for NonSyncError { + /// # fn description(&self) -> &str { + /// # "oops!" + /// # } + /// # } + /// # + /// # impl Display for NonSyncError { + /// # fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// # write!(f, "oops!") + /// # } + /// # } + /// + /// fn returns_error() -> Result<(), NonSyncError> { + /// // Do stuff + /// # Ok(()) + /// } + /// + /// fn my_function() -> Result<(), Error> { + /// // without the map_err here, we end up with a compile error + /// // complaining that NonSyncError doesn't implement Sync. + /// returns_error().map_err(SyncFailure::new)?; + /// // Do more stuff + /// # Ok(()) + /// } + /// # + /// # fn main() { + /// # my_function().unwrap(); + /// # } + /// ``` + /// + pub fn new(err: E) -> Self { + SyncFailure { + inner: Mutex::new(err), + } + } +} + +impl<T> Display for SyncFailure<T> +where + T: Display, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.lock().unwrap().fmt(f) + } +} + +impl<T> Debug for SyncFailure<T> +where + T: Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (*self.inner.lock().unwrap()).fmt(f) + } +} + +impl<E: Error + Send + 'static> Fail for SyncFailure<E> {} |