From de82983e60991822e4195eb6d4a3001d2d6ffc62 Mon Sep 17 00:00:00 2001 From: Owen Sanchez Date: Fri, 30 Jun 2017 21:07:12 -0700 Subject: [PATCH 1/9] Add support for customizing traits derived (broken currently) --- src/error_chain.rs | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/error_chain.rs b/src/error_chain.rs index 9b95a77d3..f3c89d2ef 100644 --- a/src/error_chain.rs +++ b/src/error_chain.rs @@ -2,15 +2,20 @@ #[doc(hidden)] #[macro_export] macro_rules! impl_error_chain_processed { - // Default values for `types`. + // Default values for `types` and `derive`. ( + // FIXME does not work if either types or derive isn't empty types {} + derive {} $( $rest: tt )* ) => { impl_error_chain_processed! { types { Error, ErrorKind, ResultExt, Result; } + derive { + Debug; + } $( $rest )* } }; @@ -22,6 +27,7 @@ macro_rules! impl_error_chain_processed { } $( $rest: tt )* ) => { + log_syntax!(rest: $($rest)*); impl_error_chain_processed! { types { $error_name, $error_kind_name, @@ -40,6 +46,10 @@ macro_rules! impl_error_chain_processed { $result_ext_name:ident; } + derive { + $($trait:ident),*; + } + links { $( $link_variant:ident ( $link_error_path:path, $link_kind_path:path ) $( #[$meta_links:meta] )*; ) * @@ -350,48 +360,59 @@ macro_rules! impl_error_chain_processed { #[macro_export] macro_rules! error_chain_processing { ( - ({}, $b:tt, $c:tt, $d:tt) + ({}, $b:tt, $c:tt, $d:tt, $e:tt) types $content:tt $( $tail:tt )* ) => { error_chain_processing! { - ($content, $b, $c, $d) + ($content, $b, $c, $d, $e) + $($tail)* + } + }; + ( + ($a:tt, {}, $c:tt, $d:tt, $e:tt) + derive $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($a, $content, $c, $d, $e) $($tail)* } }; ( - ($a:tt, {}, $c:tt, $d:tt) + ($a:tt, $b:tt, {}, $d:tt, $e:tt) links $content:tt $( $tail:tt )* ) => { error_chain_processing! { - ($a, $content, $c, $d) + ($a, $b, $content, $d, $e) $($tail)* } }; ( - ($a:tt, $b:tt, {}, $d:tt) + ($a:tt, $b:tt, $c:tt, {}, $e:tt) foreign_links $content:tt $( $tail:tt )* ) => { error_chain_processing! { - ($a, $b, $content, $d) + ($a, $b, $c, $content, $e) $($tail)* } }; ( - ($a:tt, $b:tt, $c:tt, {}) + ($a:tt, $b:tt, $c:tt, $d:tt, {}) errors $content:tt $( $tail:tt )* ) => { error_chain_processing! { - ($a, $b, $c, $content) + ($a, $b, $c, $d, $content) $($tail)* } }; - ( ($a:tt, $b:tt, $c:tt, $d:tt) ) => { + ( ($a:tt, $b:tt, $c:tt, $d:tt, $e:tt) ) => { impl_error_chain_processed! { types $a + derive $e links $b foreign_links $c errors $d @@ -404,7 +425,7 @@ macro_rules! error_chain_processing { macro_rules! error_chain { ( $( $block_name:ident { $( $block_content:tt )* } )* ) => { error_chain_processing! { - ({}, {}, {}, {}) + ({}, {}, {}, {}, {}) $($block_name { $( $block_content )* })* } }; From 3c5bfed47b679f474565d1a327871876bc527bcd Mon Sep 17 00:00:00 2001 From: Owen Sanchez Date: Fri, 30 Jun 2017 22:46:10 -0700 Subject: [PATCH 2/9] Fix macro problems (the feature is still useless though) --- src/error_chain.rs | 15 +++++---------- src/example_generated.rs | 14 +++++++++++++- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/error_chain.rs b/src/error_chain.rs index f3c89d2ef..421becfcd 100644 --- a/src/error_chain.rs +++ b/src/error_chain.rs @@ -4,18 +4,13 @@ macro_rules! impl_error_chain_processed { // Default values for `types` and `derive`. ( - // FIXME does not work if either types or derive isn't empty types {} - derive {} $( $rest: tt )* ) => { impl_error_chain_processed! { types { Error, ErrorKind, ResultExt, Result; } - derive { - Debug; - } $( $rest )* } }; @@ -47,7 +42,7 @@ macro_rules! impl_error_chain_processed { } derive { - $($trait:ident),*; + $($trait:ident),* } links { @@ -412,10 +407,10 @@ macro_rules! error_chain_processing { ( ($a:tt, $b:tt, $c:tt, $d:tt, $e:tt) ) => { impl_error_chain_processed! { types $a - derive $e - links $b - foreign_links $c - errors $d + derive $b + links $c + foreign_links $d + errors $e } }; } diff --git a/src/example_generated.rs b/src/example_generated.rs index 413407cae..5e5bdfc54 100644 --- a/src/example_generated.rs +++ b/src/example_generated.rs @@ -21,7 +21,11 @@ /// Another code generated by the macro. pub mod inner { - error_chain!{} + error_chain! { + derive { + Send + } + } } error_chain! { @@ -35,4 +39,12 @@ error_chain! { #[doc = "A custom error kind."] Custom } + derive { + Send + } +} + +fn foo() {} +fn bar() { + foo::(); } From 012c6219a4cebccfc7e0ef6246bf2dd2d45fd5b3 Mon Sep 17 00:00:00 2001 From: Owen Sanchez Date: Sat, 1 Jul 2017 12:24:21 -0700 Subject: [PATCH 3/9] Add generated trait --- src/error_chain.rs | 23 ++++++++++++++++++++--- src/example_generated.rs | 6 +++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/error_chain.rs b/src/error_chain.rs index 421becfcd..63bc511dc 100644 --- a/src/error_chain.rs +++ b/src/error_chain.rs @@ -42,7 +42,7 @@ macro_rules! impl_error_chain_processed { } derive { - $($trait:ident),* + $($bound:ident),* } links { @@ -60,6 +60,10 @@ macro_rules! impl_error_chain_processed { } ) => { + use ::std::fmt::Debug; + use ::std::error::Error as StdError; + create_super_trait!(Trait: Debug, StdError, Send $(, $bound)*); + /// The Error type. /// /// This tuple struct is made of two elements: @@ -69,7 +73,7 @@ macro_rules! impl_error_chain_processed { /// internals, containing: /// - a backtrace, generated when the error is created. /// - an error chain, used for the implementation of `Error::cause()`. - #[derive(Debug)] + #[derive(Debug, $($bound),*)] pub struct $error_name( // The members must be `pub` for `links`. /// The kind of the error. @@ -256,7 +260,7 @@ macro_rules! impl_error_chain_processed { impl_error_chain_kind! { /// The kind of an error. - #[derive(Debug)] + #[derive(Debug, $($bound),*)] pub enum $error_kind_name { /// A convenient variant for String. @@ -426,6 +430,19 @@ macro_rules! error_chain { }; } +/// Macro used to generate traits with `Self` bounds +#[macro_export] +#[doc(hidden)] +macro_rules! create_super_trait { + ($name:ident: $($bound:ident),*) => { + create_super_trait!($name: $($bound +)*); + }; + ($name:ident: $bound_1:ident + $($bound_2:tt +)*) => { + trait $name: $bound_1 $(+ $bound_2)* {} + impl $name for T {} + }; +} + /// Macro used to manage the `backtrace` feature. /// /// See diff --git a/src/example_generated.rs b/src/example_generated.rs index 5e5bdfc54..c818b3b6e 100644 --- a/src/example_generated.rs +++ b/src/example_generated.rs @@ -23,7 +23,7 @@ pub mod inner { error_chain! { derive { - Send + PartialEq, Eq } } } @@ -40,11 +40,11 @@ error_chain! { Custom } derive { - Send + PartialEq, Eq } } -fn foo() {} +fn foo() {} fn bar() { foo::(); } From 85a69304cb42e2dcf34b939bd52b52bb0fc4aa25 Mon Sep 17 00:00:00 2001 From: Owen Sanchez Date: Sat, 1 Jul 2017 14:19:12 -0700 Subject: [PATCH 4/9] Add generic parameter to some types (errors can now add trait bounds) --- src/backtrace.rs | 2 +- src/error_chain.rs | 6 ++--- src/example_generated.rs | 7 ++--- src/lib.rs | 57 ++++++++++++++++++++++------------------ 4 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/backtrace.rs b/src/backtrace.rs index d558ae814..912601f53 100644 --- a/src/backtrace.rs +++ b/src/backtrace.rs @@ -43,7 +43,7 @@ mod imp { }; ENABLED.store(enabled as usize + 1, Ordering::SeqCst); if !enabled { - return InternalBacktrace { backtrace: None } + return InternalBacktrace { backtrace: None }; } } 1 => return InternalBacktrace { backtrace: None }, diff --git a/src/error_chain.rs b/src/error_chain.rs index 63bc511dc..5c1a4ef43 100644 --- a/src/error_chain.rs +++ b/src/error_chain.rs @@ -80,13 +80,13 @@ macro_rules! impl_error_chain_processed { pub $error_kind_name, /// Contains the error chain and the backtrace. #[doc(hidden)] - pub $crate::State, + pub $crate::State, ); - impl $crate::ChainedError for $error_name { + impl $crate::ChainedError for $error_name { type ErrorKind = $error_kind_name; - fn new(kind: $error_kind_name, state: $crate::State) -> $error_name { + fn new(kind: $error_kind_name, state: $crate::State) -> $error_name { $error_name(kind, state) } diff --git a/src/example_generated.rs b/src/example_generated.rs index c818b3b6e..0ddbd8d46 100644 --- a/src/example_generated.rs +++ b/src/example_generated.rs @@ -20,10 +20,11 @@ //! arise frequently. /// Another code generated by the macro. + pub mod inner { error_chain! { derive { - PartialEq, Eq + PartialEq } } } @@ -40,11 +41,11 @@ error_chain! { Custom } derive { - PartialEq, Eq + PartialEq } } -fn foo() {} +fn foo() {} fn bar() { foo::(); } diff --git a/src/lib.rs b/src/lib.rs index ac185c643..1d30882f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -539,6 +539,7 @@ use std::error; use std::iter::Iterator; use std::fmt; +use std::marker::PhantomData; #[macro_use] mod impl_error_chain_kind; @@ -581,18 +582,21 @@ impl<'a> Iterator for Iter<'a> { /// This trait is implemented on all the errors generated by the `error_chain` /// macro. -pub trait ChainedError: error::Error + Send + 'static { +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; + 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(error: E, kind: K) -> Self - where Self: Sized, - E: ::std::error::Error + Send + 'static, - K: Into; + where + Self: Sized, + E: ::std::error::Error + Send + 'static, + K: Into; /// Returns the kind of the error. fn kind(&self) -> &Self::ErrorKind; @@ -608,31 +612,36 @@ pub trait ChainedError: error::Error + Send + 'static { /// /// The full cause chain and backtrace, if present, will be printed. fn display_chain<'a>(&'a self) -> DisplayChain<'a, Self> { - DisplayChain(self) + DisplayChain(self, PhantomData) } /// Extends the error chain with a new entry. fn chain_err(self, error: F) -> Self - where F: FnOnce() -> EK, - EK: Into; + where + F: FnOnce() -> EK, + EK: Into; /// Creates an error from its parts. #[doc(hidden)] - fn new(kind: Self::ErrorKind, state: State) -> Self where Self: Sized; + 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)] fn extract_backtrace(e: &(error::Error + Send + 'static)) -> Option - where Self: Sized; + where + Self: Sized; } /// A struct which formats an error for output. #[derive(Debug)] -pub struct DisplayChain<'a, T: 'a + ?Sized>(&'a T); +pub struct DisplayChain<'a, T: 'a + ?Sized, S: ?Sized>(&'a T, PhantomData); -impl<'a, T> fmt::Display for DisplayChain<'a, T> - where T: ChainedError +impl<'a, T, S> fmt::Display for DisplayChain<'a, T, S> +where + T: ChainedError, { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { // Keep `try!` for 1.10 support @@ -653,15 +662,16 @@ impl<'a, T> fmt::Display for DisplayChain<'a, T> /// Common state between errors. #[derive(Debug)] #[doc(hidden)] -pub struct State { +pub struct State { /// Next error in the error chain. - pub next_error: Option>, + pub next_error: Option>, /// Backtrace for the current error. pub backtrace: InternalBacktrace, } -impl Default for State { - fn default() -> State { +impl Default for State { + #[cfg(feature = "backtrace")] + fn default() -> Self { State { next_error: None, backtrace: InternalBacktrace::new(), @@ -669,21 +679,18 @@ impl Default for State { } } -impl State { +impl State +where + T: error::Error + Send + 'static, +{ /// Creates a new State type pub fn new(e: Box) -> State { - let backtrace = CE::extract_backtrace(&*e) - .unwrap_or_else(InternalBacktrace::new); + 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 From 24c953852eb468833de4aa4773880cc1d16e1eac Mon Sep 17 00:00:00 2001 From: Owen Sanchez Date: Sun, 2 Jul 2017 12:47:52 -0700 Subject: [PATCH 5/9] Fix create_super_trait macro not accepting paths to traits Re-order the derive block internally --- src/error_chain.rs | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src/error_chain.rs b/src/error_chain.rs index 5c1a4ef43..fdff4c4d0 100644 --- a/src/error_chain.rs +++ b/src/error_chain.rs @@ -41,10 +41,6 @@ macro_rules! impl_error_chain_processed { $result_ext_name:ident; } - derive { - $($bound:ident),* - } - links { $( $link_variant:ident ( $link_error_path:path, $link_kind_path:path ) $( #[$meta_links:meta] )*; ) * @@ -59,10 +55,11 @@ macro_rules! impl_error_chain_processed { $( $error_chunks:tt ) * } + derive { + $($bound:ident),* + } ) => { - use ::std::fmt::Debug; - use ::std::error::Error as StdError; - create_super_trait!(Trait: Debug, StdError, Send $(, $bound)*); + create_super_trait!(Trait: ::std::fmt::Debug, ::std::error::Error, Send $(, $bound)*); /// The Error type. /// @@ -370,7 +367,7 @@ macro_rules! error_chain_processing { }; ( ($a:tt, {}, $c:tt, $d:tt, $e:tt) - derive $content:tt + links $content:tt $( $tail:tt )* ) => { error_chain_processing! { @@ -380,7 +377,7 @@ macro_rules! error_chain_processing { }; ( ($a:tt, $b:tt, {}, $d:tt, $e:tt) - links $content:tt + foreign_links $content:tt $( $tail:tt )* ) => { error_chain_processing! { @@ -390,7 +387,7 @@ macro_rules! error_chain_processing { }; ( ($a:tt, $b:tt, $c:tt, {}, $e:tt) - foreign_links $content:tt + errors $content:tt $( $tail:tt )* ) => { error_chain_processing! { @@ -400,7 +397,7 @@ macro_rules! error_chain_processing { }; ( ($a:tt, $b:tt, $c:tt, $d:tt, {}) - errors $content:tt + derive $content:tt $( $tail:tt )* ) => { error_chain_processing! { @@ -411,10 +408,10 @@ macro_rules! error_chain_processing { ( ($a:tt, $b:tt, $c:tt, $d:tt, $e:tt) ) => { impl_error_chain_processed! { types $a - derive $b - links $c - foreign_links $d - errors $e + links $b + foreign_links $c + errors $d + derive $e } }; } @@ -434,12 +431,9 @@ macro_rules! error_chain { #[macro_export] #[doc(hidden)] macro_rules! create_super_trait { - ($name:ident: $($bound:ident),*) => { - create_super_trait!($name: $($bound +)*); - }; - ($name:ident: $bound_1:ident + $($bound_2:tt +)*) => { - trait $name: $bound_1 $(+ $bound_2)* {} - impl $name for T {} + ($name:ident: $bound_1:path, $($rest:path),*) => { + trait $name: $bound_1 $(+ $rest)* {} + impl $name for T {} }; } From ad0437c1fb4d1898f39400c4bb14a9418407d313 Mon Sep 17 00:00:00 2001 From: Owen Sanchez Date: Tue, 4 Jul 2017 12:14:23 -0700 Subject: [PATCH 6/9] Change `derive` block to take the derive macro name and path to the trait --- src/error_chain.rs | 26 +++++++++++++++++--------- src/example_generated.rs | 14 +++++++------- src/lib.rs | 18 +++++++++--------- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/error_chain.rs b/src/error_chain.rs index fdff4c4d0..557b4fabf 100644 --- a/src/error_chain.rs +++ b/src/error_chain.rs @@ -56,10 +56,10 @@ macro_rules! impl_error_chain_processed { } derive { - $($bound:ident),* + $($derive:ident, $bound:path);* } ) => { - create_super_trait!(Trait: ::std::fmt::Debug, ::std::error::Error, Send $(, $bound)*); + create_super_trait!(Trait: ::std::fmt::Debug, ::std::error::Error, $crate::ToError , Send $(, $bound)*); /// The Error type. /// @@ -70,7 +70,7 @@ macro_rules! impl_error_chain_processed { /// internals, containing: /// - a backtrace, generated when the error is created. /// - an error chain, used for the implementation of `Error::cause()`. - #[derive(Debug, $($bound),*)] + #[derive(Debug, $($derive),*)] pub struct $error_name( // The members must be `pub` for `links`. /// The kind of the error. @@ -80,6 +80,12 @@ macro_rules! impl_error_chain_processed { pub $crate::State, ); + impl $crate::ToError for $error_name { + fn to_error(&self) -> &(::std::error::Error + Send + 'static) { + self + } + } + impl $crate::ChainedError for $error_name { type ErrorKind = $error_kind_name; @@ -93,7 +99,7 @@ macro_rules! impl_error_chain_processed { fn with_chain(error: E, kind: K) -> Self - where E: ::std::error::Error + Send + 'static, + where E: $crate::ToError + ::std::error::Error + Send + 'static, K: Into { Self::with_chain(error, kind) @@ -135,7 +141,7 @@ macro_rules! impl_error_chain_processed { /// Constructs a chained error from another error and a kind, and generates a backtrace. pub fn with_chain(error: E, kind: K) -> $error_name - where E: ::std::error::Error + Send + 'static, + where E: Trait + 'static, K: Into<$error_kind_name> { $error_name::with_boxed_chain(Box::new(error), kind) @@ -188,7 +194,7 @@ macro_rules! impl_error_chain_processed { #[allow(unknown_lints, unused_doc_comment)] fn cause(&self) -> Option<&::std::error::Error> { match self.1.next_error { - Some(ref c) => Some(&**c), + Some(ref c) => Some(c.to_error()), None => { match self.0 { $( @@ -257,7 +263,7 @@ macro_rules! impl_error_chain_processed { impl_error_chain_kind! { /// The kind of an error. - #[derive(Debug, $($bound),*)] + #[derive(Debug, $($derive),*)] pub enum $error_kind_name { /// A convenient variant for String. @@ -326,12 +332,14 @@ macro_rules! impl_error_chain_processed { EK: Into<$error_kind_name>; } - impl $result_ext_name for ::std::result::Result where E: ::std::error::Error + Send + 'static { + impl $result_ext_name for ::std::result::Result + where E: Trait + 'static + { fn chain_err(self, callback: F) -> ::std::result::Result where F: FnOnce() -> EK, EK: Into<$error_kind_name> { self.map_err(move |e| { - let state = $crate::State::new::<$error_name>(Box::new(e), ); + let state = $crate::State::new::<$error_name>(Box::new(e)); $crate::ChainedError::new(callback().into(), state) }) } diff --git a/src/example_generated.rs b/src/example_generated.rs index 0ddbd8d46..81a23f845 100644 --- a/src/example_generated.rs +++ b/src/example_generated.rs @@ -24,7 +24,7 @@ pub mod inner { error_chain! { derive { - PartialEq + PartialEq, PartialEq } } } @@ -34,18 +34,18 @@ error_chain! { Inner(inner::Error, inner::ErrorKind) #[doc = "Link to another `ErrorChain`."]; } foreign_links { - Io(::std::io::Error) #[doc = "Link to a `std::error::Error` type."]; + //Io(::std::io::Error) #[doc = "Link to a `std::error::Error` type."]; } errors { #[doc = "A custom error kind."] Custom } derive { - PartialEq + PartialEq, PartialEq } } -fn foo() {} -fn bar() { - foo::(); -} +//fn foo() {} +//fn bar() { + //foo::(); +//} diff --git a/src/lib.rs b/src/lib.rs index 1d30882f0..72e5b4c1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -360,7 +360,6 @@ //! mod utils { //! error_chain! { //! errors { -//! BadStuff { //! description("bad stuff") //! } //! } @@ -593,10 +592,9 @@ pub trait ChainedError: error::Error + Send + 'static { /// Constructs a chained error from another error and a kind, and generates a backtrace. fn with_chain(error: E, kind: K) -> Self - where - Self: Sized, - E: ::std::error::Error + Send + 'static, - K: Into; + where Self: Sized, + E: ToError + ::std::error::Error + Send + 'static, + K: Into; /// Returns the kind of the error. fn kind(&self) -> &Self::ErrorKind; @@ -630,9 +628,11 @@ pub trait ChainedError: error::Error + Send + 'static { /// Returns the first known backtrace, either from its State or from one /// of the errors from `foreign_links`. #[doc(hidden)] - fn extract_backtrace(e: &(error::Error + Send + 'static)) -> Option - where - Self: Sized; + fn extract_backtrace(e: &(error::Error + Send + 'static)) -> Option; +} + +pub trait ToError { + fn to_error(&self) -> &(error::Error + Send + 'static); } /// A struct which formats an error for output. @@ -669,7 +669,7 @@ pub struct State { pub backtrace: InternalBacktrace, } -impl Default for State { +impl Default for State { #[cfg(feature = "backtrace")] fn default() -> Self { State { From 4cb94bc83171401b4fb5079b084e1e73267fdbc7 Mon Sep 17 00:00:00 2001 From: Owen Sanchez Date: Tue, 17 Oct 2017 11:31:27 -0700 Subject: [PATCH 7/9] Fix conflicts --- src/error_chain.rs | 30 +++++++++++++++++++++--------- src/example_generated.rs | 8 ++++---- src/lib.rs | 15 +++++++++++---- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/error_chain.rs b/src/error_chain.rs index 557b4fabf..f8c4b21af 100644 --- a/src/error_chain.rs +++ b/src/error_chain.rs @@ -42,7 +42,8 @@ macro_rules! impl_error_chain_processed { } links { - $( $link_variant:ident ( $link_error_path:path, $link_kind_path:path ) + $( $link_variant:ident ( $link_error_path:path, $link_kind_path:path, + $link_trait_path:path ) $( #[$meta_links:meta] )*; ) * } @@ -70,7 +71,8 @@ macro_rules! impl_error_chain_processed { /// internals, containing: /// - a backtrace, generated when the error is created. /// - an error chain, used for the implementation of `Error::cause()`. - #[derive(Debug, $($derive),*)] + //#[derive(Debug, $($derive),*)] + #[derive(Debug)] pub struct $error_name( // The members must be `pub` for `links`. /// The kind of the error. @@ -148,7 +150,7 @@ macro_rules! impl_error_chain_processed { } /// Construct a chained error from another boxed error and a kind, and generates a backtrace - pub fn with_boxed_chain(error: Box<::std::error::Error + Send>, kind: K) + pub fn with_boxed_chain(error: Box, kind: K) -> $error_name where K: Into<$error_kind_name> { @@ -222,7 +224,7 @@ macro_rules! impl_error_chain_processed { fn from(e: $link_error_path) -> Self { $error_name( $error_kind_name::$link_variant(e.0), - e.1, + ::State { next_error: e.1.next_error.map(|e| $crate::ConvertErrorTrait::convert(e)), backtrace: e.1.backtrace }, ) } } @@ -332,7 +334,7 @@ macro_rules! impl_error_chain_processed { EK: Into<$error_kind_name>; } - impl $result_ext_name for ::std::result::Result + impl $result_ext_name for ::std::result::Result where E: Trait + 'static { fn chain_err(self, callback: F) -> ::std::result::Result @@ -354,8 +356,6 @@ macro_rules! impl_error_chain_processed { }) } } - - }; } @@ -440,9 +440,21 @@ macro_rules! error_chain { #[doc(hidden)] macro_rules! create_super_trait { ($name:ident: $bound_1:path, $($rest:path),*) => { - trait $name: $bound_1 $(+ $rest)* {} + pub trait $name: $bound_1 $(+ $rest)* {} impl $name for T {} - }; + + pub trait ConvertErrorTrait { + type Target: ?Sized; + fn convert(self: Box) -> Box; + } + + impl ConvertErrorTrait for T { + type Target = Trait + 'static; + fn convert(self: Box) -> Box { + Box::new(self) as Box + } + } +}; } /// Macro used to manage the `backtrace` feature. diff --git a/src/example_generated.rs b/src/example_generated.rs index 81a23f845..127fcd7f4 100644 --- a/src/example_generated.rs +++ b/src/example_generated.rs @@ -24,14 +24,14 @@ pub mod inner { error_chain! { derive { - PartialEq, PartialEq + //PartialEq, PartialEq } } } error_chain! { links { - Inner(inner::Error, inner::ErrorKind) #[doc = "Link to another `ErrorChain`."]; + Inner(inner::Error, inner::ErrorKind, inner::Trait) #[doc = "Link to another `ErrorChain`."]; } foreign_links { //Io(::std::io::Error) #[doc = "Link to a `std::error::Error` type."]; @@ -41,11 +41,11 @@ error_chain! { Custom } derive { - PartialEq, PartialEq + //PartialEq, PartialEq } } //fn foo() {} //fn bar() { - //foo::(); +//foo::(); //} diff --git a/src/lib.rs b/src/lib.rs index 72e5b4c1c..58846308e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![deny(missing_docs)] +//#![deny(missing_docs)] #![allow(unknown_lints)] // to be removed when unused_doc_comments lints is merged #![doc(html_root_url = "https://docs.rs/error-chain/0.11.0")] @@ -592,7 +592,8 @@ pub trait ChainedError: error::Error + Send + 'static { /// Constructs a chained error from another error and a kind, and generates a backtrace. fn with_chain(error: E, kind: K) -> Self - where Self: Sized, + where + Self: Sized, E: ToError + ::std::error::Error + Send + 'static, K: Into; @@ -609,7 +610,7 @@ pub trait ChainedError: error::Error + Send + 'static { /// context of this error. /// /// The full cause chain and backtrace, if present, will be printed. - fn display_chain<'a>(&'a self) -> DisplayChain<'a, Self> { + fn display_chain<'a>(&'a self) -> DisplayChain<'a, Self, S> { DisplayChain(self, PhantomData) } @@ -635,6 +636,12 @@ pub trait ToError { fn to_error(&self) -> &(error::Error + Send + 'static); } +impl ToError for Box { + fn to_error(&self) -> &(error::Error + Send + 'static) { + self + } +} + /// A struct which formats an error for output. #[derive(Debug)] pub struct DisplayChain<'a, T: 'a + ?Sized, S: ?Sized>(&'a T, PhantomData); @@ -681,7 +688,7 @@ impl Default for State { impl State where - T: error::Error + Send + 'static, + T: ToError + ?Sized, { /// Creates a new State type pub fn new(e: Box) -> State { From f190643ae3a644dcc51997ba48ad5c81d1d0aadc Mon Sep 17 00:00:00 2001 From: Owen Sanchez Date: Wed, 18 Oct 2017 11:18:45 -0700 Subject: [PATCH 8/9] Add missing type parameter Add temporary #![feature(log_syntax)] --- src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 58846308e..51ae9da16 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,8 @@ #![allow(unknown_lints)] // to be removed when unused_doc_comments lints is merged #![doc(html_root_url = "https://docs.rs/error-chain/0.11.0")] +#![feature(log_syntax)] + //! A library for consistent and reliable error handling //! //! error-chain makes it easy to take full advantage of Rust's @@ -691,7 +693,7 @@ where T: ToError + ?Sized, { /// Creates a new State type - pub fn new(e: Box) -> State { + pub fn new>(e: Box) -> State { let backtrace = CE::extract_backtrace(&*e).unwrap_or_else(InternalBacktrace::new); State { next_error: Some(e), From 1decfb0197cdc22720fa39c982d456492c3363b4 Mon Sep 17 00:00:00 2001 From: Owen Sanchez Date: Wed, 25 Oct 2017 10:06:57 -0700 Subject: [PATCH 9/9] Rename State to InternalState and make it generic --- src/error_chain.rs | 128 +++++++++++++++++++++++++++------------ src/example_generated.rs | 2 +- src/lib.rs | 63 ++++++++++++------- 3 files changed, 130 insertions(+), 63 deletions(-) diff --git a/src/error_chain.rs b/src/error_chain.rs index f8c4b21af..e6852ae1b 100644 --- a/src/error_chain.rs +++ b/src/error_chain.rs @@ -9,7 +9,7 @@ macro_rules! impl_error_chain_processed { ) => { impl_error_chain_processed! { types { - Error, ErrorKind, ResultExt, Result; + Error, ErrorKind, ResultExt, Result, State, Trait; } $( $rest )* } @@ -18,15 +18,16 @@ macro_rules! impl_error_chain_processed { ( types { $error_name:ident, $error_kind_name:ident, - $result_ext_name:ident, $result_name:ident; + $result_ext_name:ident, $result_name:ident, + $state_name:ident, $trait_name:ident; } $( $rest: tt )* ) => { - log_syntax!(rest: $($rest)*); impl_error_chain_processed! { types { $error_name, $error_kind_name, - $result_ext_name; + $result_ext_name, $state_name, + $trait_name; } $( $rest )* } @@ -38,12 +39,13 @@ macro_rules! impl_error_chain_processed { ( types { $error_name:ident, $error_kind_name:ident, - $result_ext_name:ident; + $result_ext_name:ident, $state_name:ident, + $trait_name:ident; } links { $( $link_variant:ident ( $link_error_path:path, $link_kind_path:path, - $link_trait_path:path ) + $link_trait_path:path, $link_state_path:path ) $( #[$meta_links:meta] )*; ) * } @@ -60,7 +62,17 @@ macro_rules! impl_error_chain_processed { $($derive:ident, $bound:path);* } ) => { - create_super_trait!(Trait: ::std::fmt::Debug, ::std::error::Error, $crate::ToError , Send $(, $bound)*); + create_super_trait!($trait_name: ::std::fmt::Debug, ::std::error::Error, $crate::ToError, Send, + Sync $(, $bound)*); + + impl<'a> ::std::error::Error for &'a $trait_name { + fn cause(&self) -> Option<&::std::error::Error> { + (*self).cause() + } + fn description(&self) -> &str { + (*self).description() + } + } /// The Error type. /// @@ -79,19 +91,51 @@ macro_rules! impl_error_chain_processed { pub $error_kind_name, /// Contains the error chain and the backtrace. #[doc(hidden)] - pub $crate::State, + pub $crate::InternalState<$state_name>, ); - impl $crate::ToError for $error_name { - fn to_error(&self) -> &(::std::error::Error + Send + 'static) { - self + #[derive(Debug, $($derive),*)] + pub struct $state_name { + next_error: Option>, + } + + impl $state_name { + pub fn new(error: Box<$trait_name>) -> Self { + Self { + next_error: Some(error), + } + } + } + + impl Default for $state_name { + fn default() -> Self { + Self { + next_error: None, + } + } + } + impl $crate::State for $state_name { + type Error = $trait_name; + + fn new(error: Box) -> Self { + Self { + next_error: Some(error), + } + } + + fn next_error(&self) -> &Option> { + &self.next_error + } + + fn into_next_error(self) -> Option> { + self.next_error } } - impl $crate::ChainedError for $error_name { + impl $crate::ChainedError<$state_name> for $error_name { type ErrorKind = $error_kind_name; - fn new(kind: $error_kind_name, state: $crate::State) -> $error_name { + fn new(kind: $error_kind_name, state: $crate::InternalState<$state_name>) -> $error_name { $error_name(kind, state) } @@ -101,7 +145,7 @@ macro_rules! impl_error_chain_processed { fn with_chain(error: E, kind: K) -> Self - where E: $crate::ToError + ::std::error::Error + Send + 'static, + where E: $crate::ToError + ::std::error::Error + Send + Sync + 'static, K: Into { Self::with_chain(error, kind) @@ -136,27 +180,27 @@ macro_rules! impl_error_chain_processed { pub fn from_kind(kind: $error_kind_name) -> $error_name { $error_name( kind, - $crate::State::default(), + $crate::InternalState::default(), ) } /// Constructs a chained error from another error and a kind, and generates a backtrace. pub fn with_chain(error: E, kind: K) -> $error_name - where E: Trait + 'static, + where E: $trait_name + '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 - pub fn with_boxed_chain(error: Box, kind: K) + pub fn with_boxed_chain(error: Box<$trait_name>, kind: K) -> $error_name where K: Into<$error_kind_name> { $error_name( kind.into(), - $crate::State::new::<$error_name>(error, ), + $crate::InternalState::new::<$error_name>(error), ) } @@ -172,7 +216,7 @@ macro_rules! impl_error_chain_processed { /// Returns the backtrace associated with this error. pub fn backtrace(&self) -> Option<&$crate::Backtrace> { - self.1.backtrace() + self.1.backtrace.as_backtrace() } /// Extends the error chain with a new entry. @@ -195,20 +239,26 @@ macro_rules! impl_error_chain_processed { #[allow(unknown_lints, unused_doc_comment)] fn cause(&self) -> Option<&::std::error::Error> { - match self.1.next_error { - Some(ref c) => Some(c.to_error()), + let state = &self.1; + let error; + let next_error = state.next_error(); + + match *next_error { + Some(ref c) => error = Some(&*c.to_error()), None => { match self.0 { $( $(#[$meta_foreign_links])* $error_kind_name::$foreign_link_variant(ref foreign_err) => { - foreign_err.cause() + error = foreign_err.cause() } ) * - _ => None + _ => error = None } } } + + error } } @@ -219,12 +269,23 @@ macro_rules! impl_error_chain_processed { } $( + $(#[$meta_links])* + impl From<$link_state_path> for $state_name { + fn from(e: $link_state_path) -> Self { + Self { + next_error: $crate::State::into_next_error(e).map(|e| unsafe { + Box::new(e) as Box<$trait_name> + }) + } + } + } + $(#[$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), - ::State { next_error: e.1.next_error.map(|e| $crate::ConvertErrorTrait::convert(e)), backtrace: e.1.backtrace }, + ::InternalState { inner: e.1.inner.into(), backtrace: e.1.backtrace }, ) } } @@ -335,13 +396,14 @@ macro_rules! impl_error_chain_processed { } impl $result_ext_name for ::std::result::Result - where E: Trait + 'static + where E: $trait_name + Sync + 'static, + $state_name: $crate::State, { fn chain_err(self, callback: F) -> ::std::result::Result where F: FnOnce() -> EK, EK: Into<$error_kind_name> { self.map_err(move |e| { - let state = $crate::State::new::<$error_name>(Box::new(e)); + let state = $crate::InternalState::new::<$error_name>(Box::new(e)); $crate::ChainedError::new(callback().into(), state) }) } @@ -441,19 +503,7 @@ macro_rules! error_chain { macro_rules! create_super_trait { ($name:ident: $bound_1:path, $($rest:path),*) => { pub trait $name: $bound_1 $(+ $rest)* {} - impl $name for T {} - - pub trait ConvertErrorTrait { - type Target: ?Sized; - fn convert(self: Box) -> Box; - } - - impl ConvertErrorTrait for T { - type Target = Trait + 'static; - fn convert(self: Box) -> Box { - Box::new(self) as Box - } - } + impl $name for T {} }; } diff --git a/src/example_generated.rs b/src/example_generated.rs index 127fcd7f4..92de92c67 100644 --- a/src/example_generated.rs +++ b/src/example_generated.rs @@ -31,7 +31,7 @@ pub mod inner { error_chain! { links { - Inner(inner::Error, inner::ErrorKind, inner::Trait) #[doc = "Link to another `ErrorChain`."]; + Inner(inner::Error, inner::ErrorKind, inner::Trait, inner::State) #[doc = "Link to another `ErrorChain`."]; } foreign_links { //Io(::std::io::Error) #[doc = "Link to a `std::error::Error` type."]; diff --git a/src/lib.rs b/src/lib.rs index 51ae9da16..fa0659883 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,6 @@ #![allow(unknown_lints)] // to be removed when unused_doc_comments lints is merged #![doc(html_root_url = "https://docs.rs/error-chain/0.11.0")] -#![feature(log_syntax)] - //! A library for consistent and reliable error handling //! //! error-chain makes it easy to take full advantage of Rust's @@ -583,7 +581,7 @@ impl<'a> Iterator for Iter<'a> { /// This trait is implemented on all the errors generated by the `error_chain` /// macro. -pub trait ChainedError: error::Error + Send + 'static { +pub trait ChainedError: error::Error + Send + Sync + 'static { /// Associated kind type. type ErrorKind; @@ -596,7 +594,7 @@ pub trait ChainedError: error::Error + Send + 'static { fn with_chain(error: E, kind: K) -> Self where Self: Sized, - E: ToError + ::std::error::Error + Send + 'static, + E: ToError + ::std::error::Error + Send + Sync + 'static, K: Into; /// Returns the kind of the error. @@ -624,7 +622,7 @@ pub trait ChainedError: error::Error + Send + 'static { /// Creates an error from its parts. #[doc(hidden)] - fn new(kind: Self::ErrorKind, state: State) -> Self + fn new(kind: Self::ErrorKind, state: InternalState) -> Self where Self: Sized; @@ -635,21 +633,28 @@ pub trait ChainedError: error::Error + Send + 'static { } pub trait ToError { - fn to_error(&self) -> &(error::Error + Send + 'static); -} + fn to_error(&self) -> &error::Error + where Self: error::Error + { + self + } -impl ToError for Box { - fn to_error(&self) -> &(error::Error + Send + 'static) { + fn to_error_send(&self) -> &(error::Error + Send) + where Self: error::Error + Send + { self } } +impl ToError for T {} + /// A struct which formats an error for output. #[derive(Debug)] -pub struct DisplayChain<'a, T: 'a + ?Sized, S: ?Sized>(&'a T, PhantomData); +pub struct DisplayChain<'a, T: 'a + ?Sized, S: State>(&'a T, PhantomData); impl<'a, T, S> fmt::Display for DisplayChain<'a, T, S> where + S: State, T: ChainedError, { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { @@ -668,38 +673,50 @@ where } } +pub trait State: Default { + type Error: ?Sized; + + fn new(error: Box) -> Self; + fn next_error(&self) -> &Option>; + fn into_next_error(self) -> Option>; +} /// Common state between errors. #[derive(Debug)] #[doc(hidden)] -pub struct State { - /// Next error in the error chain. - pub next_error: Option>, +pub struct InternalState { + /// The user's state type generated by the `error_chain` macro + pub inner: S, /// Backtrace for the current error. pub backtrace: InternalBacktrace, } -impl Default for State { +impl Default for InternalState { #[cfg(feature = "backtrace")] fn default() -> Self { - State { - next_error: None, + InternalState { + inner: Default::default(), backtrace: InternalBacktrace::new(), } } } -impl State -where - T: ToError + ?Sized, +impl InternalState + where S::Error: error::Error + Send + Sync, { /// Creates a new State type - pub fn new>(e: Box) -> State { - let backtrace = CE::extract_backtrace(&*e).unwrap_or_else(InternalBacktrace::new); - State { - next_error: Some(e), + pub fn new>(e: Box) -> InternalState { + let backtrace = CE::extract_backtrace(&e).unwrap_or_else(InternalBacktrace::new); + + InternalState { + inner: S::new(e), backtrace: backtrace, } } + + /// Returns the next error in the error chain + pub fn next_error(&self) -> &Option> { + self.inner.next_error() + } } /// Exits a function early with an error