From a040044529b21d8d7ba4c4e7cff833ef3d15deee Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Tue, 8 Jan 2019 15:33:12 +0100 Subject: [PATCH] add more traits and macros Namely: * ChainErrorFrom * IntoChainError * minto_cherr! * into_cherr! * strerr! Also make derive_str_cherr! struct public --- Cargo.toml | 2 +- examples/tutorial10.rs | 1 + examples/tutorial11.rs | 2 + src/lib.rs | 104 +++++++++++++++++++++++++++++++++++++++-- 4 files changed, 104 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7a47e7a..d262af5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chainerror" -version = "0.2.0" +version = "0.3.0" authors = ["Harald Hoyer "] edition = "2018" license = "MIT/Apache-2.0" diff --git a/examples/tutorial10.rs b/examples/tutorial10.rs index 5d1aa1e..b22d0b7 100644 --- a/examples/tutorial10.rs +++ b/examples/tutorial10.rs @@ -30,6 +30,7 @@ impl ::std::fmt::Display for Func1ErrorKind { } } } +impl ::std::error::Error for Func1ErrorKind {} fn func1() -> ChainResult<(), Func1ErrorKind> { func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?; diff --git a/examples/tutorial11.rs b/examples/tutorial11.rs index 336b7fb..46cf00c 100644 --- a/examples/tutorial11.rs +++ b/examples/tutorial11.rs @@ -36,6 +36,8 @@ impl ::std::fmt::Debug for Func1ErrorKind { } } +impl ::std::error::Error for Func1ErrorKind {} + fn func1() -> ChainResult<(), Func1ErrorKind> { func2().map_err(|e| cherr!(e, Func1ErrorKind::Func2))?; let filename = String::from("bar.txt"); diff --git a/src/lib.rs b/src/lib.rs index 166ddf3..c4a9b50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -369,7 +369,7 @@ impl ChainError { ~~~ **/ - pub fn kind<'a>(&'a self) -> &'a T { + pub fn kind(&self) -> &T { &self.kind } } @@ -395,7 +395,10 @@ impl ChainErrorDown for ChainError { fn downcast_chain_ref(&self) -> Option<&ChainError> { if self.is_chain::() { - unsafe { Some(&*(self as *const dyn Error as *const &ChainError)) } + #[allow(clippy::cast_ptr_alignment)] + unsafe { + Some(&*(self as *const dyn Error as *const &ChainError)) + } } else { None } @@ -403,7 +406,10 @@ impl ChainErrorDown for ChainError { fn downcast_chain_mut(&mut self) -> Option<&mut ChainError> { if self.is_chain::() { - unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError)) } + #[allow(clippy::cast_ptr_alignment)] + unsafe { + Some(&mut *(self as *mut dyn Error as *mut &mut ChainError)) + } } else { None } @@ -523,6 +529,48 @@ impl Debug for ChainError { } } +pub trait ChainErrorFrom: Sized { + fn chain_error_from(_: T, line_filename: Option<(u32, &'static str)>) -> ChainError; +} + +pub trait IntoChainError: Sized { + fn into_chain_error(self, line_filename: Option<(u32, &'static str)>) -> ChainError; +} + +impl IntoChainError for T +where + U: ChainErrorFrom, +{ + fn into_chain_error(self, line_filename: Option<(u32, &'static str)>) -> ChainError { + U::chain_error_from(self, line_filename) + } +} + +impl ChainErrorFrom for U +where + T: Into, + U: 'static + Display + Debug, +{ + fn chain_error_from(t: T, line_filename: Option<(u32, &'static str)>) -> ChainError { + let e: U = t.into(); + ChainError::<_>::new(e, None, line_filename) + } +} + +#[macro_export] +macro_rules! minto_cherr { + ( ) => { + |e| e.into_chain_error(Some((line!(), file!()))) + }; +} + +#[macro_export] +macro_rules! into_cherr { + ( $t:expr ) => { + $t.into_chain_error(Some((line!(), file!()))) + }; +} + /** creates a new `ChainError` # Examples @@ -719,6 +767,54 @@ macro_rules! mstrerr { }; } +/** convenience macro for cherr!(T(format!(…))) where T(String) +~~~rust +# use crate::chainerror::*; +# use std::error::Error; +# use std::result::Result; +# +derive_str_cherr!(Func2Error); + +fn func2() -> ChainResult<(), Func2Error> { + let filename = "foo.txt"; + Err(strerr!(Func2Error, "Error reading '{}'", filename)) +} + +derive_str_cherr!(Func1Error); + +fn func1() -> Result<(), Box> { + func2().map_err(mstrerr!(Func1Error, "func1 error"))?; + Ok(()) +} +# +# fn main() { +# if let Err(e) = func1() { +# if let Some(f1err) = e.downcast_chain_ref::() { +# assert!(f1err.find_cause::>().is_some()); +# assert!(f1err.find_chain_cause::().is_some()); +# } else { +# panic!(); +# } +# } else { +# unreachable!(); +# } +# } +~~~ + +**/ +#[macro_export] +macro_rules! strerr { + ( $t:ident, $v:expr $(, $more:expr)* ) => { + cherr!($t (format!($v, $( $more , )* ))) + }; + ( $t:path, $v:expr $(, $more:expr)* ) => { + cherr!($t (format!($v, $( $more , )* ))) + }; + ( $v:expr $(, $more:expr)* ) => { + cherr!(format!($v, $( $more , )* )) + }; +} + /** convenience macro to create a "new type" T(String) and implement Display + Debug for T ~~~rust @@ -765,7 +861,7 @@ fn func1() -> Result<(), Box> { #[macro_export] macro_rules! derive_str_cherr { ($e:ident) => { - struct $e(String); + pub struct $e(pub String); impl ::std::fmt::Display for $e { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "{}", self.0)