diff options
Diffstat (limited to 'third_party/rust/error-chain/src')
-rw-r--r-- | third_party/rust/error-chain/src/backtrace.rs | 111 | ||||
-rw-r--r-- | third_party/rust/error-chain/src/error_chain.rs | 564 | ||||
-rw-r--r-- | third_party/rust/error-chain/src/example_generated.rs | 38 | ||||
-rw-r--r-- | third_party/rust/error-chain/src/impl_error_chain_kind.rs | 383 | ||||
-rw-r--r-- | third_party/rust/error-chain/src/lib.rs | 824 | ||||
-rw-r--r-- | third_party/rust/error-chain/src/quick_main.rs | 81 |
6 files changed, 2001 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 + } + } +} diff --git a/third_party/rust/error-chain/src/error_chain.rs b/third_party/rust/error-chain/src/error_chain.rs new file mode 100644 index 0000000000..8382709621 --- /dev/null +++ b/third_party/rust/error-chain/src/error_chain.rs @@ -0,0 +1,564 @@ +#[doc(hidden)] +#[macro_export] +#[cfg(not(has_error_source))] +macro_rules! impl_error_chain_cause_or_source { + ( + types { + $error_kind_name:ident + } + + foreign_links { + $( $foreign_link_variant:ident ( $foreign_link_error_path:path ) + $( #[$meta_foreign_links:meta] )*; )* + } + ) => { + #[allow(unknown_lints, renamed_and_removed_lints)] + #[allow(unused_doc_comment, unused_doc_comments)] + fn cause(&self) -> Option<&::std::error::Error> { + match self.1.next_error { + Some(ref c) => Some(&**c), + None => { + match self.0 { + $( + $(#[$meta_foreign_links])* + $error_kind_name::$foreign_link_variant(ref foreign_err) => { + foreign_err.cause() + } + ) * + _ => None + } + } + } + } + }; +} + +#[cfg(has_error_source)] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_error_chain_cause_or_source { + ( + types { + $error_kind_name:ident + } + + foreign_links { + $( $foreign_link_variant:ident ( $foreign_link_error_path:path ) + $( #[$meta_foreign_links:meta] )*; )* + } + ) => { + #[allow(unknown_lints, renamed_and_removed_lints, bare_trait_objects)] + #[allow(unused_doc_comment, unused_doc_comments)] + fn source(&self) -> Option<&(std::error::Error + 'static)> { + match self.1.next_error { + Some(ref c) => Some(&**c), + None => { + match self.0 { + $( + $(#[$meta_foreign_links])* + $error_kind_name::$foreign_link_variant(ref foreign_err) => { + foreign_err.source() + } + ) * + _ => None + } + } + } + } + }; +} + +/// Conditional usage of deprecated Error::description +#[doc(hidden)] +#[cfg(has_error_description_deprecated)] +#[macro_export(local_inner_macros)] +macro_rules! call_to_deprecated_description { + ($e:ident) => { + "" + }; +} + +#[doc(hidden)] +#[cfg(not(has_error_description_deprecated))] +#[macro_export(local_inner_macros)] +macro_rules! call_to_deprecated_description { + ($e:ident) => { + ::std::error::Error::description($e) + }; +} + +/// Prefer to use `error_chain` instead of this macro. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! impl_error_chain_processed { + // Default values for `types`. + ( + types {} + $( $rest: tt )* + ) => { + impl_error_chain_processed! { + types { + Error, ErrorKind, ResultExt, Result; + } + $( $rest )* + } + }; + // With `Result` wrapper. + ( + types { + $error_name:ident, $error_kind_name:ident, + $result_ext_name:ident, $result_name:ident; + } + $( $rest: tt )* + ) => { + impl_error_chain_processed! { + types { + $error_name, $error_kind_name, + $result_ext_name; + } + $( $rest )* + } + /// Convenient wrapper around `std::Result`. + #[allow(unused)] + pub type $result_name<T> = ::std::result::Result<T, $error_name>; + }; + + // With `Msg` variant. + ( + types { + $error_name:ident, $error_kind_name:ident, $($types:tt)* + } + links $links:tt + foreign_links $foreign_links:tt + errors { $($errors:tt)* } + ) => { + impl_error_chain_processed! { + types { + $error_name, $error_kind_name, $($types)* + } + skip_msg_variant + links $links + foreign_links $foreign_links + errors { + /// A convenient variant for String. + Msg(s: String) { + description(&s) + display("{}", s) + } + + $($errors)* + } + } + + impl<'a> From<&'a str> for $error_kind_name { + fn from(s: &'a str) -> Self { + $error_kind_name::Msg(s.into()) + } + } + + impl From<String> for $error_kind_name { + fn from(s: String) -> Self { + $error_kind_name::Msg(s) + } + } + + impl<'a> From<&'a str> for $error_name { + fn from(s: &'a str) -> Self { + Self::from_kind(s.into()) + } + } + + impl From<String> for $error_name { + fn from(s: String) -> Self { + Self::from_kind(s.into()) + } + } + }; + + // Without `Result` wrapper or `Msg` variant. + ( + types { + $error_name:ident, $error_kind_name:ident, + $result_ext_name:ident; + } + + skip_msg_variant + + links { + $( $link_variant:ident ( $link_error_path:path, $link_kind_path:path ) + $( #[$meta_links:meta] )*; ) * + } + + foreign_links { + $( $foreign_link_variant:ident ( $foreign_link_error_path:path ) + $( #[$meta_foreign_links:meta] )*; )* + } + + errors { + $( $error_chunks:tt ) * + } + + ) => { + /// The Error type. + /// + /// This tuple struct is made of two elements: + /// + /// - an `ErrorKind` which is used to determine the type of the error. + /// - An internal `State`, not meant for direct use outside of `error_chain` + /// internals, containing: + /// - a backtrace, generated when the error is created. + /// - an error chain, used for the implementation of `Error::cause()`. + #[derive(Debug)] + pub struct $error_name( + // The members must be `pub` for `links`. + /// The kind of the error. + pub $error_kind_name, + /// Contains the error chain and the backtrace. + #[doc(hidden)] + pub $crate::State, + ); + + impl $crate::ChainedError for $error_name { + type ErrorKind = $error_kind_name; + + fn new(kind: $error_kind_name, state: $crate::State) -> $error_name { + $error_name(kind, state) + } + + fn from_kind(kind: Self::ErrorKind) -> Self { + Self::from_kind(kind) + } + + fn with_chain<E, K>(error: E, kind: K) + -> Self + where E: ::std::error::Error + Send + 'static, + K: Into<Self::ErrorKind> + { + Self::with_chain(error, kind) + } + + fn kind(&self) -> &Self::ErrorKind { + self.kind() + } + + fn iter(&self) -> $crate::Iter { + $crate::Iter::new(Some(self)) + } + + fn chain_err<F, EK>(self, error: F) -> Self + where F: FnOnce() -> EK, + EK: Into<$error_kind_name> { + self.chain_err(error) + } + + fn backtrace(&self) -> Option<&$crate::Backtrace> { + self.backtrace() + } + + impl_extract_backtrace!($error_name + $error_kind_name + $([$link_error_path, $(#[$meta_links])*])*); + } + + #[allow(dead_code)] + impl $error_name { + /// Constructs an error from a kind, and generates a backtrace. + pub fn from_kind(kind: $error_kind_name) -> $error_name { + $error_name( + kind, + $crate::State::default(), + ) + } + + /// Constructs a chained error from another error and a kind, and generates a backtrace. + pub fn with_chain<E, K>(error: E, kind: K) + -> $error_name + where E: ::std::error::Error + Send + 'static, + K: Into<$error_kind_name> + { + $error_name::with_boxed_chain(Box::new(error), kind) + } + + /// Construct a chained error from another boxed error and a kind, and generates a backtrace + #[allow(unknown_lints, bare_trait_objects)] + pub fn with_boxed_chain<K>(error: Box<::std::error::Error + Send>, kind: K) + -> $error_name + where K: Into<$error_kind_name> + { + $error_name( + kind.into(), + $crate::State::new::<$error_name>(error, ), + ) + } + + /// Returns the kind of the error. + pub fn kind(&self) -> &$error_kind_name { + &self.0 + } + + /// Iterates over the error chain. + pub fn iter(&self) -> $crate::Iter { + $crate::ChainedError::iter(self) + } + + /// Returns the backtrace associated with this error. + pub fn backtrace(&self) -> Option<&$crate::Backtrace> { + self.1.backtrace() + } + + /// Extends the error chain with a new entry. + pub fn chain_err<F, EK>(self, error: F) -> $error_name + where F: FnOnce() -> EK, EK: Into<$error_kind_name> { + $error_name::with_chain(self, Self::from_kind(error().into())) + } + + /// A short description of the error. + /// This method is identical to [`Error::description()`](https://doc.rust-lang.org/nightly/std/error/trait.Error.html#tymethod.description) + pub fn description(&self) -> &str { + self.0.description() + } + } + + impl ::std::error::Error for $error_name { + #[cfg(not(has_error_description_deprecated))] + fn description(&self) -> &str { + self.description() + } + + impl_error_chain_cause_or_source!{ + types { + $error_kind_name + } + foreign_links { + $( $foreign_link_variant ( $foreign_link_error_path ) + $( #[$meta_foreign_links] )*; )* + } + } + } + + impl ::std::fmt::Display for $error_name { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::std::fmt::Display::fmt(&self.0, f) + } + } + + $( + $(#[$meta_links])* + impl From<$link_error_path> for $error_name { + fn from(e: $link_error_path) -> Self { + $error_name( + $error_kind_name::$link_variant(e.0), + e.1, + ) + } + } + ) * + + $( + $(#[$meta_foreign_links])* + impl From<$foreign_link_error_path> for $error_name { + fn from(e: $foreign_link_error_path) -> Self { + $error_name::from_kind( + $error_kind_name::$foreign_link_variant(e) + ) + } + } + ) * + + impl From<$error_kind_name> for $error_name { + fn from(e: $error_kind_name) -> Self { + $error_name::from_kind(e) + } + } + + // The ErrorKind type + // -------------- + + impl_error_chain_kind! { + /// The kind of an error. + #[derive(Debug)] + pub enum $error_kind_name { + $( + $(#[$meta_links])* + $link_variant(e: $link_kind_path) { + description(e.description()) + display("{}", e) + } + ) * + + $( + $(#[$meta_foreign_links])* + $foreign_link_variant(err: $foreign_link_error_path) { + description(call_to_deprecated_description!(err)) + display("{}", err) + } + ) * + + $($error_chunks)* + } + } + + $( + $(#[$meta_links])* + impl From<$link_kind_path> for $error_kind_name { + fn from(e: $link_kind_path) -> Self { + $error_kind_name::$link_variant(e) + } + } + ) * + + impl From<$error_name> for $error_kind_name { + fn from(e: $error_name) -> Self { + e.0 + } + } + + // The ResultExt trait defines the `chain_err` method. + + /// Additional methods for `Result`, for easy interaction with this crate. + pub trait $result_ext_name<T> { + /// If the `Result` is an `Err` then `chain_err` evaluates the closure, + /// which returns *some type that can be converted to `ErrorKind`*, boxes + /// the original error to store as the cause, then returns a new error + /// containing the original error. + fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name> + where F: FnOnce() -> EK, + EK: Into<$error_kind_name>; + } + + impl<T, E> $result_ext_name<T> for ::std::result::Result<T, E> where E: ::std::error::Error + Send + 'static { + fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name> + where F: FnOnce() -> EK, + EK: Into<$error_kind_name> { + self.map_err(move |e| { + let state = $crate::State::new::<$error_name>(Box::new(e), ); + $crate::ChainedError::new(callback().into(), state) + }) + } + } + + impl<T> $result_ext_name<T> for ::std::option::Option<T> { + fn chain_err<F, EK>(self, callback: F) -> ::std::result::Result<T, $error_name> + where F: FnOnce() -> EK, + EK: Into<$error_kind_name> { + self.ok_or_else(move || { + $crate::ChainedError::from_kind(callback().into()) + }) + } + } + + + }; +} + +/// Internal macro used for reordering of the fields. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! error_chain_processing { + ( + ({}, $($rest:tt)*) + types $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($content, $($rest)*) + $($tail)* + } + }; + + ( + ($a:tt, {}, $($rest:tt)*) + links $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($a, $content, $($rest)*) + $($tail)* + } + }; + + ( + ($a:tt, $b:tt, {}, $($rest:tt)*) + foreign_links $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($a, $b, $content, $($rest)*) + $($tail)* + } + }; + + ( + ($a:tt, $b:tt, $c:tt, {}, $($rest:tt)*) + errors $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($a, $b, $c, $content, $($rest)*) + $($tail)* + } + }; + + ( + ($a:tt, $b:tt, $c:tt, $d:tt, {}, $($rest:tt)*) + skip_msg_variant + $( $tail:tt )* + ) => { + error_chain_processing! { + ($a, $b, $c, $d, {skip_msg_variant}, $($rest)*) + $($tail)* + } + }; + + ( ($a:tt, $b:tt, $c:tt, $d:tt, {$($e:tt)*},) ) => { + impl_error_chain_processed! { + types $a + $($e)* + links $b + foreign_links $c + errors $d + } + }; +} + +/// Macro for generating error types and traits. See crate level documentation for details. +#[macro_export(local_inner_macros)] +macro_rules! error_chain { + ( $($args:tt)* ) => { + error_chain_processing! { + ({}, {}, {}, {}, {},) + $($args)* + } + }; +} + +/// Macro used to manage the `backtrace` feature. +/// +/// See +/// https://www.reddit.com/r/rust/comments/57virt/hey_rustaceans_got_an_easy_question_ask_here/da5r4ti/?context=3 +/// for more details. +#[macro_export] +#[doc(hidden)] +macro_rules! impl_extract_backtrace { + ($error_name: ident + $error_kind_name: ident + $([$link_error_path: path, $(#[$meta_links: meta])*])*) => { + #[allow(unknown_lints, renamed_and_removed_lints, bare_trait_objects)] + #[allow(unused_doc_comment, unused_doc_comments)] + fn extract_backtrace(e: &(::std::error::Error + Send + 'static)) + -> Option<$crate::InternalBacktrace> { + if let Some(e) = e.downcast_ref::<$error_name>() { + return Some(e.1.backtrace.clone()); + } + $( + $( #[$meta_links] )* + { + if let Some(e) = e.downcast_ref::<$link_error_path>() { + return Some(e.1.backtrace.clone()); + } + } + ) * + None + } + } +} diff --git a/third_party/rust/error-chain/src/example_generated.rs b/third_party/rust/error-chain/src/example_generated.rs new file mode 100644 index 0000000000..c0f4d23014 --- /dev/null +++ b/third_party/rust/error-chain/src/example_generated.rs @@ -0,0 +1,38 @@ +//! These modules show an example of code generated by the macro. **IT MUST NOT BE +//! USED OUTSIDE THIS CRATE**. +//! +//! This is the basic error structure. You can see that `ErrorKind` +//! has been populated in a variety of ways. All `ErrorKind`s get a +//! `Msg` variant for basic errors. When strings are converted to +//! `ErrorKind`s they become `ErrorKind::Msg`. The "links" defined in +//! the macro are expanded to the `Inner` variant, and the +//! "foreign links" to the `Io` variant. +//! +//! Both types come with a variety of `From` conversions as well: +//! `Error` can be created from `ErrorKind`, `&str` and `String`, +//! and the `links` and `foreign_links` error types. `ErrorKind` +//! can be created from the corresponding `ErrorKind`s of the link +//! types, as well as from `&str` and `String`. +//! +//! `into()` and `From::from` are used heavily to massage types into +//! the right shape. Which one to use in any specific case depends on +//! the influence of type inference, but there are some patterns that +//! arise frequently. + +/// Another code generated by the macro. +pub mod inner { + error_chain! {} +} + +error_chain! { + links { + Inner(inner::Error, inner::ErrorKind) #[doc = "Link to another `ErrorChain`."]; + } + foreign_links { + Io(::std::io::Error) #[doc = "Link to a `std::io::Error` type."]; + } + errors { + #[doc = "A custom error kind."] + Custom + } +} diff --git a/third_party/rust/error-chain/src/impl_error_chain_kind.rs b/third_party/rust/error-chain/src/impl_error_chain_kind.rs new file mode 100644 index 0000000000..4acf8435b2 --- /dev/null +++ b/third_party/rust/error-chain/src/impl_error_chain_kind.rs @@ -0,0 +1,383 @@ +/// From https://github.com/tailhook/quick-error +/// Changes: +/// - replace `impl Error` by `impl Item::description` +/// - $imeta + +/// Because of the `#[macro_export(local_inner_macros)]` usage on `impl_error_chain_kind` that macro +/// will only look inside this crate for macros to invoke. So using `stringify` or `write` from +/// the standard library will fail. Thus we here create simple wrappers for them that are not +/// exported as `local_inner_macros`, and thus they can in turn use the standard library macros. +#[macro_export] +macro_rules! stringify_internal { + ($($t:tt)*) => { stringify!($($t)*) } +} + +/// Macro used interally for output expanding an expression +#[macro_export] +macro_rules! write_internal { + ($dst:expr, $($arg:tt)*) => (write!($dst, $($arg)*)) +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! impl_error_chain_kind { + ( $(#[$meta:meta])* + pub enum $name:ident { $($chunks:tt)* } + ) => { + impl_error_chain_kind!(SORT [pub enum $name $(#[$meta])* ] + items [] buf [] + queue [ $($chunks)* ]); + }; + // Queue is empty, can do the work + (SORT [pub enum $name:ident $( #[$meta:meta] )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [ ] + queue [ ] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [pub enum $name $( #[$meta] )*] + body [] + queue [$($( #[$imeta] )* + => $iitem: $imode [$( $ivar: $ityp ),*] )*] + ); + impl_error_chain_kind!(IMPLEMENTATIONS $name {$( + $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*} + )*}); + $( + impl_error_chain_kind!(ERROR_CHECK $imode $($ifuncs)*); + )* + }; + // Add meta to buffer + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )*] + queue [ #[$qmeta:meta] $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* #[$qmeta] ] + queue [$( $tail )*]); + }; + // Add ident to buffer + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )*] + queue [ $qitem:ident $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* + => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$(#[$bmeta])* => $qitem : UNIT [ ] ] + queue [$( $tail )*]); + }; + // Flush buffer on meta after ident + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ #[$qmeta:meta] $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + enum [$(#[$bmeta])* => $bitem: $bmode $(( $($btyp),* ))*] + items [$($( #[$imeta:meta] )* + => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $bitem: $bmode [$( $bvar:$btyp ),*] {} ] + buf [ #[$qmeta] ] + queue [$( $tail )*]); + }; + // Add tuple enum-variant + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] + queue [($( $qvar:ident: $qtyp:ty ),+) $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* => $bitem: TUPLE [$( $qvar:$qtyp ),+] ] + queue [$( $tail )*] + ); + }; + // Add struct enum-variant - e.g. { descr: &'static str } + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] + queue [{ $( $qvar:ident: $qtyp:ty ),+} $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),+] ] + queue [$( $tail )*]); + }; + // Add struct enum-variant, with excess comma - e.g. { descr: &'static str, } + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] + queue [{$( $qvar:ident: $qtyp:ty ),+ ,} $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),+] ] + queue [$( $tail )*]); + }; + // Add braces and flush always on braces + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ {$( $qfuncs:tt )*} $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {$( $qfuncs )*} ] + buf [ ] + queue [$( $tail )*]); + }; + // Flush buffer on double ident + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ $qitem:ident $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ] + buf [ => $qitem : UNIT [ ] ] + queue [$( $tail )*]); + }; + // Flush buffer on end + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ ] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ] + buf [ ] + queue [ ]); + }; + // Public enum (Queue Empty) + (ENUM_DEFINITION [pub enum $name:ident $( #[$meta:meta] )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [ ] + ) => { + $(#[$meta])* + pub enum $name { + $( + $(#[$imeta])* + $iitem $(($( $ttyp ),+))* $({$( $svar: $styp ),*})*, + )* + + #[doc(hidden)] + __Nonexhaustive {} + } + }; + // Unit variant + (ENUM_DEFINITION [$( $def:tt )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [$( #[$qmeta:meta] )* + => $qitem:ident: UNIT [ ] $( $queue:tt )*] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ] + body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* + $( #[$qmeta] )* => $qitem () {} ] + queue [ $($queue)* ] + ); + }; + // Tuple variant + (ENUM_DEFINITION [$( $def:tt )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [$( #[$qmeta:meta] )* + => $qitem:ident: TUPLE [$( $qvar:ident: $qtyp:ty ),+] $( $queue:tt )*] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ] + body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* + $( #[$qmeta] )* => $qitem (($( $qtyp ),+)) {} ] + queue [ $($queue)* ] + ); + }; + // Struct variant + (ENUM_DEFINITION [$( $def:tt )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [$( #[$qmeta:meta] )* + => $qitem:ident: STRUCT [$( $qvar:ident: $qtyp:ty ),*] $( $queue:tt )*] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ] + body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* + $( #[$qmeta] )* => $qitem () {{$( $qvar: $qtyp ),*}} ] + queue [ $($queue)* ] + ); + }; + (IMPLEMENTATIONS + $name:ident {$( + $item:ident: $imode:tt [$(#[$imeta:meta])*] [$( $var:ident: $typ:ty ),*] {$( $funcs:tt )*} + )*} + ) => { + #[allow(unknown_lints, unused, renamed_and_removed_lints)] + #[allow(unused_doc_comment, unused_doc_comments)] + impl ::std::fmt::Display for $name { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) + -> ::std::fmt::Result + { + match *self { + $( + $(#[$imeta])* + impl_error_chain_kind!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { + let display_fn = impl_error_chain_kind!(FIND_DISPLAY_IMPL + $name $item: $imode + {$( $funcs )*}); + + display_fn(self, fmt) + } + )* + + _ => Ok(()) + } + } + } + #[allow(unknown_lints, unused, renamed_and_removed_lints)] + #[allow(unused_doc_comment, unused_doc_comments)] + impl $name { + /// A string describing the error kind. + pub fn description(&self) -> &str { + match *self { + $( + $(#[$imeta])* + impl_error_chain_kind!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { + impl_error_chain_kind!(FIND_DESCRIPTION_IMPL + $item: $imode self fmt [$( $var ),*] + {$( $funcs )*}) + } + )* + + _ => "", + } + } + } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*} + ) => { + |impl_error_chain_kind!(IDENT $self_): &$name, f: &mut ::std::fmt::Formatter| { + write_internal!(f, $( $exprs )*) + } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { display($pattern:expr) $( $tail:tt )*} + ) => { + |_, f: &mut ::std::fmt::Formatter| { write_internal!(f, $pattern) } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { display($pattern:expr, $( $exprs:tt )*) $( $tail:tt )*} + ) => { + |_, f: &mut ::std::fmt::Formatter| { write_internal!(f, $pattern, $( $exprs )*) } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { $t:tt $( $tail:tt )*} + ) => { + impl_error_chain_kind!(FIND_DISPLAY_IMPL + $name $item: $imode + {$( $tail )*}) + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { } + ) => { + |self_: &$name, f: &mut ::std::fmt::Formatter| { + write_internal!(f, "{}", self_.description()) + } + }; + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { description($expr:expr) $( $tail:tt )*} + ) => { + $expr + }; + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { $t:tt $( $tail:tt )*} + ) => { + impl_error_chain_kind!(FIND_DESCRIPTION_IMPL + $item: $imode $me $fmt [$( $var ),*] + {$( $tail )*}) + }; + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { } + ) => { + stringify_internal!($item) + }; + (ITEM_BODY $(#[$imeta:meta])* $item:ident: UNIT + ) => { }; + (ITEM_BODY $(#[$imeta:meta])* $item:ident: TUPLE + [$( $typ:ty ),*] + ) => { + ($( $typ ),*) + }; + (ITEM_BODY $(#[$imeta:meta])* $item:ident: STRUCT + [$( $var:ident: $typ:ty ),*] + ) => { + {$( $var:$typ ),*} + }; + (ITEM_PATTERN $name:ident $item:ident: UNIT [] + ) => { + $name::$item + }; + (ITEM_PATTERN $name:ident $item:ident: TUPLE + [$( ref $var:ident ),*] + ) => { + $name::$item ($( ref $var ),*) + }; + (ITEM_PATTERN $name:ident $item:ident: STRUCT + [$( ref $var:ident ),*] + ) => { + $name::$item {$( ref $var ),*} + }; + // This one should match all allowed sequences in "funcs" but not match + // anything else. + // This is to contrast FIND_* clauses which just find stuff they need and + // skip everything else completely + (ERROR_CHECK $imode:tt display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt display($pattern: expr) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt display($pattern: expr, $( $exprs:tt )*) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt description($expr:expr) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt ) => {}; + (ERROR_CHECK_COMMA $imode:tt , $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK $imode $($tail)*); }; + (ERROR_CHECK_COMMA $imode:tt $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK $imode $($tail)*); }; + // Utility functions + (IDENT $ident:ident) => { $ident } +} diff --git a/third_party/rust/error-chain/src/lib.rs b/third_party/rust/error-chain/src/lib.rs new file mode 100644 index 0000000000..43d2d5f479 --- /dev/null +++ b/third_party/rust/error-chain/src/lib.rs @@ -0,0 +1,824 @@ +#![deny(missing_docs)] +#![doc(html_root_url = "https://docs.rs/error-chain/0.12.4")] + +//! A library for consistent and reliable error handling +//! +//! error-chain makes it easy to take full advantage of Rust's +//! powerful error handling features without the overhead of +//! maintaining boilerplate error types and conversions. It implements +//! an opinionated strategy for defining your own error types, as well +//! as conversions from others' error types. +//! +//! ## Quick start +//! +//! If you just want to set up your new project with error-chain, +//! follow the [quickstart.rs] template, and read this [intro] +//! to error-chain. +//! +//! [quickstart.rs]: https://github.com/rust-lang-nursery/error-chain/blob/master/examples/quickstart.rs +//! [intro]: http://brson.github.io/2016/11/30/starting-with-error-chain +//! +//! ## Why error chain? +//! +//! * error-chain is easy to configure. Handle errors robustly with minimal +//! effort. +//! * Basic error handling requires no maintenance of custom error types +//! nor the [`From`] conversions that make `?` work. +//! * error-chain scales from simple error handling strategies to more +//! rigorous. Return formatted strings for simple errors, only +//! introducing error variants and their strong typing as needed for +//! advanced error recovery. +//! * error-chain makes it trivial to correctly manage the [cause] of +//! the errors generated by your own code. This is the "chaining" +//! in "error-chain". +//! +//! [cause]: https://doc.rust-lang.org/std/error/trait.Error.html#method.cause +//! +//! ## Principles of error-chain +//! +//! error-chain is based on the following principles: +//! +//! * No error should ever be discarded. This library primarily +//! makes it easy to "chain" errors with the [`chain_err`] method. +//! * Introducing new errors is trivial. Simple errors can be introduced +//! at the error site with just a string. +//! * Handling errors is possible with pattern matching. +//! * Conversions between error types are done in an automatic and +//! consistent way - [`From`] conversion behavior is never specified +//! explicitly. +//! * Errors implement [`Send`]. +//! * Errors can carry backtraces. +//! +//! Similar to other libraries like [error-type] and [quick-error], +//! this library introduces the error chaining mechanism originally +//! employed by Cargo. The [`error_chain!`] macro declares the types +//! and implementation boilerplate necessary for fulfilling a +//! particular error-handling strategy. Most importantly it defines a +//! custom error type (called [`Error`] by convention) and the [`From`] +//! conversions that let the `?` operator work. +//! +//! This library differs in a few ways from previous error libs: +//! +//! * Instead of defining the custom [`Error`] type as an enum, it is a +//! struct containing an [`ErrorKind`][] (which defines the +//! [`description`] and [`display_chain`] methods for the error), an opaque, +//! optional, boxed [`std::error::Error`]` + `[`Send`]` + 'static` object +//! (which defines the [`cause`], and establishes the links in the +//! error chain), and a [`Backtrace`]. +//! * The macro also defines a [`ResultExt`] trait that defines a +//! [`chain_err`] method. This method on all [`std::error::Error`]` + `[`Send`]` + 'static` +//! types extends the error chain by boxing the current +//! error into an opaque object and putting it inside a new concrete +//! error. +//! * It provides automatic [`From`] conversions between other error types +//! defined by the [`error_chain!`] that preserve type information, +//! and facilitate seamless error composition and matching of composed +//! errors. +//! * It provides automatic [`From`] conversions between any other error +//! type that hides the type of the other error in the [`cause`] box. +//! * If `RUST_BACKTRACE` is enabled, it collects a single backtrace at +//! the earliest opportunity and propagates it down the stack through +//! [`From`] and [`ResultExt`] conversions. +//! +//! To accomplish its goals it makes some tradeoffs: +//! +//! * The split between the [`Error`] and [`ErrorKind`] types can make it +//! slightly more cumbersome to instantiate new (unchained) errors, +//! requiring an [`Into`] or [`From`] conversion; as well as slightly +//! more cumbersome to match on errors with another layer of types +//! to match. +//! * Because the error type contains [`std::error::Error`]` + `[`Send`]` + 'static` objects, +//! it can't implement [`PartialEq`] for easy comparisons. +//! +//! ## Declaring error types +//! +//! Generally, you define one family of error types per crate, though +//! it's also perfectly fine to define error types on a finer-grained +//! basis, such as per module. +//! +//! Assuming you are using crate-level error types, typically you will +//! define an `errors` module and inside it call [`error_chain!`]: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! mod other_error { +//! error_chain! {} +//! } +//! +//! error_chain! { +//! // The type defined for this error. These are the conventional +//! // and recommended names, but they can be arbitrarily chosen. +//! // +//! // It is also possible to leave this section out entirely, or +//! // leave it empty, and these names will be used automatically. +//! types { +//! Error, ErrorKind, ResultExt, Result; +//! } +//! +//! // Without the `Result` wrapper: +//! // +//! // types { +//! // Error, ErrorKind, ResultExt; +//! // } +//! +//! // Automatic conversions between this error chain and other +//! // error chains. In this case, it will e.g. generate an +//! // `ErrorKind` variant called `Another` which in turn contains +//! // the `other_error::ErrorKind`, with conversions from +//! // `other_error::Error`. +//! // +//! // Optionally, some attributes can be added to a variant. +//! // +//! // This section can be empty. +//! links { +//! Another(other_error::Error, other_error::ErrorKind) #[cfg(unix)]; +//! } +//! +//! // Automatic conversions between this error chain and other +//! // error types not defined by the `error_chain!`. These will be +//! // wrapped in a new error with, in the first case, the +//! // `ErrorKind::Fmt` variant. The description and cause will +//! // forward to the description and cause of the original error. +//! // +//! // Optionally, some attributes can be added to a variant. +//! // +//! // This section can be empty. +//! foreign_links { +//! Fmt(::std::fmt::Error); +//! Io(::std::io::Error) #[cfg(unix)]; +//! } +//! +//! // Define additional `ErrorKind` variants. Define custom responses with the +//! // `description` and `display` calls. +//! errors { +//! InvalidToolchainName(t: String) { +//! description("invalid toolchain name") +//! display("invalid toolchain name: '{}'", t) +//! } +//! +//! // You can also add commas after description/display. +//! // This may work better with some editor auto-indentation modes: +//! UnknownToolchainVersion(v: String) { +//! description("unknown toolchain version"), // note the , +//! display("unknown toolchain version: '{}'", v), // trailing comma is allowed +//! } +//! } +//! +//! // If this annotation is left off, a variant `Msg(s: String)` will be added, and `From` +//! // impls will be provided for `String` and `&str` +//! skip_msg_variant +//! } +//! +//! # fn main() {} +//! ``` +//! +//! Each section, `types`, `links`, `foreign_links`, and `errors` may +//! be omitted if it is empty. +//! +//! This populates the module with a number of definitions, +//! the most important of which are the [`Error`] type +//! and the [`ErrorKind`] type. An example of generated code can be found in the +//! [example_generated](example_generated/index.html) module. +//! +//! ## Returning new errors +//! +//! Introducing new error chains, with a string message: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! {} +//! fn foo() -> Result<()> { +//! Err("foo error!".into()) +//! } +//! ``` +//! +//! Introducing new error chains, with an [`ErrorKind`]: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! error_chain! { +//! errors { FooError } +//! } +//! +//! fn foo() -> Result<()> { +//! Err(ErrorKind::FooError.into()) +//! } +//! ``` +//! +//! Note that the return type is the typedef [`Result`], which is +//! defined by the macro as `pub type Result<T> = +//! ::std::result::Result<T, Error>`. Note that in both cases +//! [`.into()`] is called to convert a type into the [`Error`] type; both +//! strings and [`ErrorKind`] have [`From`] conversions to turn them into +//! [`Error`]. +//! +//! When the error is emitted behind the `?` operator, the explicit conversion +//! isn't needed; `Err(ErrorKind)` will automatically be converted to `Err(Error)`. +//! So the below is equivalent to the previous: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! { errors { FooError } } +//! fn foo() -> Result<()> { +//! Ok(Err(ErrorKind::FooError)?) +//! } +//! +//! fn bar() -> Result<()> { +//! Ok(Err("bogus!")?) +//! } +//! ``` +//! +//! ## The `bail!` macro +//! +//! The above method of introducing new errors works but is a little +//! verbose. Instead, we can use the [`bail!`] macro, which performs an early return +//! with conversions done automatically. +//! +//! With [`bail!`] the previous examples look like: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! { errors { FooError } } +//! fn foo() -> Result<()> { +//! if true { +//! bail!(ErrorKind::FooError); +//! } else { +//! Ok(()) +//! } +//! } +//! +//! fn bar() -> Result<()> { +//! if true { +//! bail!("bogus!"); +//! } else { +//! Ok(()) +//! } +//! } +//! ``` +//! +//! ## Chaining errors +//! error-chain supports extending an error chain by appending new errors. +//! This can be done on a Result or on an existing Error. +//! +//! To extend the error chain: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! {} +//! # fn do_something() -> Result<()> { unimplemented!() } +//! # fn test() -> Result<()> { +//! let res: Result<()> = do_something().chain_err(|| "something went wrong"); +//! # Ok(()) +//! # } +//! ``` +//! +//! [`chain_err`] can be called on any [`Result`] type where the contained +//! error type implements [`std::error::Error`]` + `[`Send`]` + 'static`, as long as +//! the [`Result`] type's corresponding [`ResultExt`] trait is in scope. If +//! the [`Result`] is an `Err` then [`chain_err`] evaluates the closure, +//! which returns *some type that can be converted to [`ErrorKind`]*, +//! boxes the original error to store as the cause, then returns a new +//! error containing the original error. +//! +//! Calling [`chain_err`][Error_chain_err] on an existing [`Error`] instance has +//! the same signature and produces the same outcome as being called on a +//! [`Result`] matching the properties described above. This is most useful when +//! partially handling errors using the [`map_err`] function. +//! +//! To chain an error directly, use [`with_chain`]: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! {} +//! # fn do_something() -> Result<()> { unimplemented!() } +//! # fn test() -> Result<()> { +//! let res: Result<()> = +//! do_something().map_err(|e| Error::with_chain(e, "something went wrong")); +//! # Ok(()) +//! # } +//! ``` +//! +//! ## Linking errors +//! +//! To convert an error from another error chain to this error chain: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # mod other { error_chain! {} } +//! error_chain! { +//! links { +//! OtherError(other::Error, other::ErrorKind); +//! } +//! } +//! +//! fn do_other_thing() -> other::Result<()> { unimplemented!() } +//! +//! # fn test() -> Result<()> { +//! let res: Result<()> = do_other_thing().map_err(|e| e.into()); +//! # Ok(()) +//! # } +//! ``` +//! +//! The [`Error`] and [`ErrorKind`] types implements [`From`] for the corresponding +//! types of all linked error chains. Linked errors do not introduce a new +//! cause to the error chain. +//! +//! ## Matching errors +//! +//! error-chain error variants are matched with simple patterns. +//! [`Error`] is a tuple struct and its first field is the [`ErrorKind`], +//! making dispatching on error kinds relatively compact: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() { +//! error_chain! { +//! errors { +//! InvalidToolchainName(t: String) { +//! description("invalid toolchain name") +//! display("invalid toolchain name: '{}'", t) +//! } +//! } +//! } +//! +//! match Error::from("error!") { +//! Error(ErrorKind::InvalidToolchainName(_), _) => { } +//! Error(ErrorKind::Msg(_), _) => { } +//! _ => { } +//! } +//! # } +//! ``` +//! +//! Chained errors are also matched with (relatively) compact syntax +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! mod utils { +//! error_chain! { +//! errors { +//! BadStuff { +//! description("bad stuff") +//! } +//! } +//! } +//! } +//! +//! mod app { +//! error_chain! { +//! links { +//! Utils(::utils::Error, ::utils::ErrorKind); +//! } +//! } +//! } +//! +//! +//! # fn main() { +//! match app::Error::from("error!") { +//! app::Error(app::ErrorKind::Utils(utils::ErrorKind::BadStuff), _) => { } +//! _ => { } +//! } +//! # } +//! ``` +//! +//! ## Inspecting errors +//! +//! An error-chain error contains information about the error itself, a backtrace, and the chain +//! of causing errors. For reporting purposes, this information can be accessed as follows. +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! use error_chain::ChainedError; // for e.display_chain() +//! +//! error_chain! { +//! errors { +//! InvalidToolchainName(t: String) { +//! description("invalid toolchain name") +//! display("invalid toolchain name: '{}'", t) +//! } +//! } +//! } +//! +//! # fn main() { +//! // Generate an example error to inspect: +//! let e = "xyzzy".parse::<i32>() +//! .chain_err(|| ErrorKind::InvalidToolchainName("xyzzy".to_string())) +//! .unwrap_err(); +//! +//! // Get the brief description of the error: +//! assert_eq!(e.description(), "invalid toolchain name"); +//! +//! // Get the display version of the error: +//! assert_eq!(e.to_string(), "invalid toolchain name: 'xyzzy'"); +//! +//! // Get the full cause and backtrace: +//! println!("{}", e.display_chain().to_string()); +//! // Error: invalid toolchain name: 'xyzzy' +//! // Caused by: invalid digit found in string +//! // stack backtrace: +//! // 0: 0x7fa9f684fc94 - backtrace::backtrace::libunwind::trace +//! // at src/backtrace/libunwind.rs:53 +//! // - backtrace::backtrace::trace<closure> +//! // at src/backtrace/mod.rs:42 +//! // 1: 0x7fa9f6850b0e - backtrace::capture::{{impl}}::new +//! // at out/capture.rs:79 +//! // [..] +//! # } +//! ``` +//! +//! The [`Error`] and [`ErrorKind`] types also allow programmatic access to these elements. +//! +//! ## Foreign links +//! +//! Errors that do not conform to the same conventions as this library +//! can still be included in the error chain. They are considered "foreign +//! errors", and are declared using the `foreign_links` block of the +//! [`error_chain!`] macro. [`Error`]s are automatically created from +//! foreign errors by the `?` operator. +//! +//! Foreign links and regular links have one crucial difference: +//! [`From`] conversions for regular links *do not introduce a new error +//! into the error chain*, while conversions for foreign links *always +//! introduce a new error into the error chain*. So for the example +//! above all errors deriving from the [`std::fmt::Error`] type will be +//! presented to the user as a new [`ErrorKind`] variant, and the +//! cause will be the original [`std::fmt::Error`] error. In contrast, when +//! `other_error::Error` is converted to `Error` the two `ErrorKind`s +//! are converted between each other to create a new `Error` but the +//! old error is discarded; there is no "cause" created from the +//! original error. +//! +//! ## Backtraces +//! +//! If the `RUST_BACKTRACE` environment variable is set to anything +//! but ``0``, the earliest non-foreign error to be generated creates +//! a single backtrace, which is passed through all [`From`] conversions +//! and [`chain_err`] invocations of compatible types. To read the +//! backtrace just call the [`backtrace`] method. +//! +//! Backtrace generation can be disabled by turning off the `backtrace` feature. +//! +//! The Backtrace contains a Vec of [`BacktraceFrame`]s that can be operated +//! on directly. For example, to only see the files and line numbers of code +//! within your own project. +//! +//! ``` +//! # #[macro_use] +//! # extern crate error_chain; +//! # mod errors { +//! # error_chain! { +//! # foreign_links { +//! # Io(::std::io::Error); +//! # } +//! # } +//! # } +//! # use errors::*; +//! # #[cfg(feature="backtrace")] +//! # fn main() { +//! if let Err(ref e) = open_file() { +//! if let Some(backtrace) = e.backtrace() { +//! let frames = backtrace.frames(); +//! for frame in frames.iter() { +//! for symbol in frame.symbols().iter() { +//! if let (Some(file), Some(lineno)) = (symbol.filename(), symbol.lineno()) { +//! if file.display().to_string()[0..3] == "src".to_string(){ +//! println!("{}:{}", file.display().to_string(), lineno); +//! } +//! } +//! } +//! } +//! } +//! }; +//! # } +//! # #[cfg(not(feature="backtrace"))] +//! # fn main() { } +//! +//! fn open_file() -> Result<()> { +//! std::fs::File::open("does_not_exist")?; +//! Ok(()) +//! } +//! ``` +//! +//! ## Iteration +//! +//! The [`iter`] method returns an iterator over the chain of error boxes. +//! +//! [error-type]: https://github.com/DanielKeep/rust-error-type +//! [quick-error]: https://github.com/tailhook/quick-error + +//! [`display_chain`]: trait.ChainedError.html#method.display_chain +//! [`error_chain!`]: macro.error_chain.html +//! [`bail!`]: macro.bail.html +//! [`Backtrace`]: struct.Backtrace.html + +//! [`Error`]: example_generated/struct.Error.html +//! [`with_chain`]: example_generated/struct.Error.html#method.with_chain +//! [Error_chain_err]: example_generated/struct.Error.html#method.chain_err +//! [`cause`]: example_generated/struct.Error.html#method.cause +//! [`backtrace`]: example_generated/struct.Error.html#method.backtrace +//! [`iter`]: example_generated/struct.Error.html#method.iter +//! [`ErrorKind`]: example_generated/enum.ErrorKind.html +//! [`description`]: example_generated/enum.ErrorKind.html#method.description +//! [`Result`]: example_generated/type.Result.html +//! [`ResultExt`]: example_generated/trait.ResultExt.html +//! [`chain_err`]: example_generated/trait.ResultExt.html#tymethod.chain_err + +//! [`std::error::Error`]: https://doc.rust-lang.org/std/error/trait.Error.html +//! [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html +//! [`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html +//! [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html +//! [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html +//! [`std::fmt::Error`]: https://doc.rust-lang.org/std/fmt/struct.Error.html +//! [`.into()`]: https://doc.rust-lang.org/std/convert/trait.Into.html#tymethod.into +//! [`map_err`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err +//! [`BacktraceFrame`]: https://docs.rs/backtrace/0.3.2/backtrace/struct.BacktraceFrame.html + +use std::error; +use std::fmt; +use std::iter::Iterator; + +#[macro_use] +mod impl_error_chain_kind; +#[macro_use] +mod error_chain; +#[macro_use] +mod quick_main; +pub use quick_main::ExitCode; +mod backtrace; +#[cfg(feature = "example_generated")] +pub mod example_generated; +pub use backtrace::Backtrace; +#[doc(hidden)] +pub use backtrace::InternalBacktrace; + +#[derive(Debug)] +#[allow(unknown_lints, bare_trait_objects)] +/// Iterator over the error chain using the `Error::cause()` method. +pub struct Iter<'a>(Option<&'a error::Error>); + +impl<'a> Iter<'a> { + /// Returns a new iterator over the error chain using `Error::cause()`. + #[allow(unknown_lints, bare_trait_objects)] + pub fn new(err: Option<&'a error::Error>) -> Iter<'a> { + Iter(err) + } +} + +#[allow(unknown_lints, bare_trait_objects)] +impl<'a> Iterator for Iter<'a> { + type Item = &'a error::Error; + + fn next<'b>(&'b mut self) -> Option<&'a error::Error> { + match self.0.take() { + Some(e) => { + self.0 = match () { + #[cfg(not(has_error_source))] + () => e.cause(), + #[cfg(has_error_source)] + () => e.source(), + }; + Some(e) + } + None => None, + } + } +} + +/// This trait is implemented on all the errors generated by the `error_chain` +/// macro. +pub trait ChainedError: error::Error + Send + 'static { + /// Associated kind type. + type ErrorKind; + + /// Constructs an error from a kind, and generates a backtrace. + fn from_kind(kind: Self::ErrorKind) -> Self + where + Self: Sized; + + /// Constructs a chained error from another error and a kind, and generates a backtrace. + fn with_chain<E, K>(error: E, kind: K) -> Self + where + Self: Sized, + E: ::std::error::Error + Send + 'static, + K: Into<Self::ErrorKind>; + + /// Returns the kind of the error. + fn kind(&self) -> &Self::ErrorKind; + + /// Iterates over the error chain. + fn iter(&self) -> Iter; + + /// Returns the backtrace associated with this error. + fn backtrace(&self) -> Option<&Backtrace>; + + /// Returns an object which implements `Display` for printing the full + /// context of this error. + /// + /// The full cause chain and backtrace, if present, will be printed. + fn display_chain<'a>(&'a self) -> DisplayChain<'a, Self> { + DisplayChain(self) + } + + /// Extends the error chain with a new entry. + fn chain_err<F, EK>(self, error: F) -> Self + where + F: FnOnce() -> EK, + EK: Into<Self::ErrorKind>; + + /// Creates an error from its parts. + #[doc(hidden)] + fn new(kind: Self::ErrorKind, state: State) -> Self + where + Self: Sized; + + /// Returns the first known backtrace, either from its State or from one + /// of the errors from `foreign_links`. + #[doc(hidden)] + #[allow(unknown_lints, bare_trait_objects)] + fn extract_backtrace(e: &(error::Error + Send + 'static)) -> Option<InternalBacktrace> + where + Self: Sized; +} + +/// A struct which formats an error for output. +#[derive(Debug)] +pub struct DisplayChain<'a, T: 'a + ?Sized>(&'a T); + +impl<'a, T> fmt::Display for DisplayChain<'a, T> +where + T: ChainedError, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + writeln!(fmt, "Error: {}", self.0)?; + + for e in self.0.iter().skip(1) { + writeln!(fmt, "Caused by: {}", e)?; + } + + if let Some(backtrace) = ChainedError::backtrace(self.0) { + writeln!(fmt, "{:?}", backtrace)?; + } + + Ok(()) + } +} + +/// Common state between errors. +#[derive(Debug)] +#[doc(hidden)] +#[allow(unknown_lints, bare_trait_objects)] +pub struct State { + /// Next error in the error chain. + pub next_error: Option<Box<error::Error + Send>>, + /// Backtrace for the current error. + pub backtrace: InternalBacktrace, +} + +impl Default for State { + fn default() -> State { + State { + next_error: None, + backtrace: InternalBacktrace::new(), + } + } +} + +impl State { + /// Creates a new State type + #[allow(unknown_lints, bare_trait_objects)] + pub fn new<CE: ChainedError>(e: Box<error::Error + Send>) -> State { + let backtrace = CE::extract_backtrace(&*e).unwrap_or_else(InternalBacktrace::new); + State { + next_error: Some(e), + backtrace: backtrace, + } + } + + /// Returns the inner backtrace if present. + pub fn backtrace(&self) -> Option<&Backtrace> { + self.backtrace.as_backtrace() + } +} + +/// Exits a function early with an error +/// +/// The `bail!` macro provides an easy way to exit a function. +/// `bail!(expr)` is equivalent to writing. +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! { } +/// # fn main() { } +/// # fn foo() -> Result<()> { +/// # let expr = ""; +/// return Err(expr.into()); +/// # } +/// ``` +/// +/// And as shorthand it takes a formatting string a la `println!`: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! { } +/// # fn main() { } +/// # fn foo() -> Result<()> { +/// # let n = 0; +/// bail!("bad number: {}", n); +/// # } +/// ``` +/// +/// # Examples +/// +/// Bailing on a custom error: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # fn main() {} +/// error_chain! { +/// errors { FooError } +/// } +/// +/// fn foo() -> Result<()> { +/// if bad_condition() { +/// bail!(ErrorKind::FooError); +/// } +/// +/// Ok(()) +/// } +/// +/// # fn bad_condition() -> bool { true } +/// ``` +/// +/// Bailing on a formatted string: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # fn main() {} +/// error_chain! { } +/// +/// fn foo() -> Result<()> { +/// if let Some(bad_num) = bad_condition() { +/// bail!("so bad: {}", bad_num); +/// } +/// +/// Ok(()) +/// } +/// +/// # fn bad_condition() -> Option<i8> { None } +/// ``` +#[macro_export] +macro_rules! bail { + ($e:expr) => { + return Err($e.into()); + }; + ($fmt:expr, $($arg:tt)+) => { + return Err(format!($fmt, $($arg)+).into()); + }; +} + +/// Exits a function early with an error if the condition is not satisfied +/// +/// The `ensure!` macro is a convenience helper that provides a way to exit +/// a function with an error if the given condition fails. +/// +/// As an example, `ensure!(condition, "error code: {}", errcode)` is equivalent to +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! { } +/// # fn main() { } +/// # fn foo() -> Result<()> { +/// # let errcode = 0u8; +/// # let condition = true; +/// if !condition { +/// bail!("error code: {}", errcode); +/// } +/// # Ok(()) +/// # } +/// ``` +/// +/// See documentation for `bail!` macro for further details. +#[macro_export(local_inner_macros)] +macro_rules! ensure { + ($cond:expr, $e:expr) => { + if !($cond) { + bail!($e); + } + }; + ($cond:expr, $fmt:expr, $($arg:tt)+) => { + if !($cond) { + bail!($fmt, $($arg)+); + } + }; +} + +#[doc(hidden)] +pub mod mock { + error_chain! {} +} diff --git a/third_party/rust/error-chain/src/quick_main.rs b/third_party/rust/error-chain/src/quick_main.rs new file mode 100644 index 0000000000..a6f093d2b3 --- /dev/null +++ b/third_party/rust/error-chain/src/quick_main.rs @@ -0,0 +1,81 @@ +/// Convenient wrapper to be able to use `?` and such in the main. You can +/// use it with a separated function: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! {} +/// # fn main() { +/// quick_main!(run); +/// # } +/// +/// fn run() -> Result<()> { +/// Err("error".into()) +/// } +/// ``` +/// +/// or with a closure: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! {} +/// # fn main() { +/// quick_main!(|| -> Result<()> { +/// Err("error".into()) +/// }); +/// # } +/// ``` +/// +/// You can also set the exit value of the process by returning a type that implements [`ExitCode`](trait.ExitCode.html): +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! {} +/// # fn main() { +/// quick_main!(run); +/// # } +/// +/// fn run() -> Result<i32> { +/// Err("error".into()) +/// } +/// ``` +#[macro_export] +macro_rules! quick_main { + ($main:expr) => { + fn main() { + use std::io::Write; + + ::std::process::exit(match $main() { + Ok(ret) => $crate::ExitCode::code(ret), + Err(ref e) => { + write!( + &mut ::std::io::stderr(), + "{}", + $crate::ChainedError::display_chain(e) + ) + .expect("Error writing to stderr"); + + 1 + } + }); + } + }; +} + +/// Represents a value that can be used as the exit status of the process. +/// See [`quick_main!`](macro.quick_main.html). +pub trait ExitCode { + /// Returns the value to use as the exit status. + fn code(self) -> i32; +} + +impl ExitCode for i32 { + fn code(self) -> i32 { + self + } +} + +impl ExitCode for () { + fn code(self) -> i32 { + 0 + } +} |