diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2017-08-29 14:15:05 +0200 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2017-09-03 15:42:03 +0200 |
commit | e77d353c526ae638085350b364ee876378f4d5f2 (patch) | |
tree | dfa19f061feff10d26a116cab9b6efc225238bb3 | |
parent | 279afd1972827a288b3f2fd066dc91130fe97789 (diff) |
Rewrite macros to do error-chain behind the scenes
26 files changed, 1155 insertions, 624 deletions
diff --git a/bin/core/imag-store/src/error.rs b/bin/core/imag-store/src/error.rs index bc248ade..d74e4a30 100644 --- a/bin/core/imag-store/src/error.rs +++ b/bin/core/imag-store/src/error.rs @@ -17,12 +17,24 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // -generate_error_module!( - generate_error_types!(StoreError, StoreErrorKind, - BackendError => "Backend Error", - NoCommandlineCall => "No commandline call" - ); -); +error_chain! { + types { + StoreError, StoreErrorKind, ResultExt, Result; + } + + errors { + BackendError { + description("Backend Error") + display("Backend Error") + } + + NoCommandlineCall { + description("No commandline call") + display("No commandline call") + } + + } +} pub use self::error::StoreError; pub use self::error::StoreErrorKind; diff --git a/lib/core/libimagerror/Cargo.toml b/lib/core/libimagerror/Cargo.toml index 5f490746..fbfd1bbb 100644 --- a/lib/core/libimagerror/Cargo.toml +++ b/lib/core/libimagerror/Cargo.toml @@ -16,3 +16,4 @@ homepage = "http://imag-pim.org" [dependencies] log = "0.3" ansi_term = "0.9" +error-chain = "0.10" diff --git a/lib/core/libimagerror/src/error_gen.rs b/lib/core/libimagerror/src/error_gen.rs index eb06692c..a03c998f 100644 --- a/lib/core/libimagerror/src/error_gen.rs +++ b/lib/core/libimagerror/src/error_gen.rs @@ -18,137 +18,54 @@ // #[macro_export] -macro_rules! generate_error_imports { - () => { - use std::error::Error; - use std::fmt::Error as FmtError; - use std::fmt::{Display, Formatter}; - - use $crate::into::IntoError; - } -} - -#[macro_export] macro_rules! generate_error_module { ( $exprs:item ) => { pub mod error { - generate_error_imports!(); $exprs } } } #[macro_export] -macro_rules! generate_custom_error_types { +macro_rules! generate_error_types { { $name: ident, $kindname: ident, - $customMemberTypeName: ident, $($kind:ident => $string:expr),* } => { - #[derive(Clone, Copy, Debug, PartialEq)] - pub enum $kindname { - $( $kind ),* - } - - impl Display for $kindname { - - fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { - let s = match *self { - $( $kindname::$kind => $string ),* - }; - try!(write!(fmt, "{}", s)); - Ok(()) - } - - } - - impl IntoError for $kindname { - type Target = $name; - - fn into_error(self) -> Self::Target { - $name::new(self, None) - } - - fn into_error_with_cause(self, cause: Box<Error>) -> Self::Target { - $name::new(self, Some(cause)) - } - - } - - #[derive(Debug)] - pub struct $name { - err_type: $kindname, - cause: Option<Box<Error>>, - custom_data: Option<$customMemberTypeName>, - } - - impl $name { - - pub fn new(errtype: $kindname, cause: Option<Box<Error>>) -> $name { - $name { - err_type: errtype, - cause: cause, - custom_data: None, - } - } - - #[allow(dead_code)] - pub fn err_type(&self) -> $kindname { - self.err_type - } - - #[allow(dead_code)] - pub fn with_custom_data(mut self, custom: $customMemberTypeName) -> $name { - self.custom_data = Some(custom); - self - } - - } - - impl Into<$name> for $kindname { - - fn into(self) -> $name { - $name::new(self, None) + error_chain! { + types { + $name, $kindname, ResultExt, Result; } - } - - impl Display for $name { - - fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { - try!(write!(fmt, "[{}]", self.err_type)); - match self.custom_data { - Some(ref c) => write!(fmt, "{}", c), - None => Ok(()), - } + links { + // None } - } - - impl Error for $name { - - fn description(&self) -> &str { - match self.err_type { - $( $kindname::$kind => $string ),* - } + foreign_links { + // None } - fn cause(&self) -> Option<&Error> { - self.cause.as_ref().map(|e| &**e) + errors { + $( + $kind { + description($string) + display($string) + } + )* } - } + generate_result_helper!($name, $kindname); + generate_option_helper!($name, $kindname); } } #[macro_export] macro_rules! generate_result_helper { - ( - $name: ident, - $kindname: ident - ) => { + { + $name:ident, $kindname:ident + } => { /// Trait to replace /// /// ```ignore @@ -163,15 +80,14 @@ macro_rules! generate_result_helper { /// foo.map_err_into(SomeType::SomeErrorKind) /// ``` /// - pub trait MapErrInto<T> { - fn map_err_into(self, error_kind: $kindname) -> Result<T, $name>; + pub trait MapErrInto<T, E: Error> { + fn map_err_into(self, error_kind: $kindname) -> ::std::result::Result<T, E>; } - impl<T, E: Error + 'static> MapErrInto<T> for Result<T, E> { + impl<T, E: Error> MapErrInto<T, E: Error> for Result<T, E> { - fn map_err_into(self, error_kind: $kindname) -> Result<T, $name> { - self.map_err(Box::new) - .map_err(|e| error_kind.into_error_with_cause(e)) + fn map_err_into(self, error_kind: $kindname) -> ::std::result::Result<T, E> { + self.chain_err(|| error_kind) } } @@ -180,10 +96,9 @@ macro_rules! generate_result_helper { #[macro_export] macro_rules! generate_option_helper { - ( - $name: ident, - $kindname: ident - ) => { + { + $name:ident, $kindname:ident + } => { /// Trait to replace /// /// ```ignore @@ -196,193 +111,45 @@ macro_rules! generate_option_helper { /// foo.ok_or_errkind(SomeType::SomeErrorKind) /// ``` pub trait OkOrErr<T> { - fn ok_or_errkind(self, kind: $kindname) -> Result<T, $name>; + fn ok_or_errkind(self, kind: $kindname) -> Result<T>; } impl<T> OkOrErr<T> for Option<T> { - fn ok_or_errkind(self, kind: $kindname) -> Result<T, $name> { - self.ok_or(kind.into_error()) + fn ok_or_errkind(self, kind: $kindname) -> Result<T> { + self.ok_or($name::from_kind(kind)) } } } } -#[macro_export] -macro_rules! generate_error_types { - ( - $name: ident, - $kindname: ident, - $($kind:ident => $string:expr),* - ) => { - #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)] - pub struct SomeNotExistingTypeWithATypeNameNoOneWillEverChoose {} - - impl Display for SomeNotExistingTypeWithATypeNameNoOneWillEverChoose { - fn fmt(&self, _: &mut Formatter) -> Result<(), FmtError> { - Ok(()) - } - } - - generate_custom_error_types!($name, $kindname, - SomeNotExistingTypeWithATypeNameNoOneWillEverChoose, - $($kind => $string),*); - - generate_result_helper!($name, $kindname); - generate_option_helper!($name, $kindname); - } -} - #[cfg(test)] #[allow(dead_code)] mod test { - generate_error_module!( - generate_error_types!(TestError, TestErrorKind, - TestErrorKindA => "testerrorkind a", - TestErrorKindB => "testerrorkind B"); - ); - - #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)] - pub struct CustomData { - pub test: i32, - pub othr: i64, - } - - impl Display for CustomData { - fn fmt(&self, _: &mut Formatter) -> Result<(), FmtError> { - Ok(()) - } - } - - generate_error_imports!(); - - #[allow(dead_code)] - generate_custom_error_types!(CustomTestError, CustomTestErrorKind, - CustomData, - CustomErrorKindA => "customerrorkind a", - CustomErrorKindB => "customerrorkind B"); - - // Allow dead code here. - // We wrote this to show that custom test types can be implemented. - #[allow(dead_code)] - impl CustomTestError { - pub fn test(&self) -> i32 { - match self.custom_data { - Some(t) => t.test, - None => 0, - } - } - - pub fn bar(&self) -> i64 { - match self.custom_data { - Some(t) => t.othr, - None => 0, - } - } - } - - - #[test] - fn test_a() { - use self::error::{TestError, TestErrorKind}; - - let kind = TestErrorKind::TestErrorKindA; - assert_eq!(String::from("testerrorkind a"), format!("{}", kind)); - - let e = TestError::new(kind, None); - assert_eq!(String::from("[testerrorkind a]"), format!("{}", e)); - } - - #[test] - fn test_b() { - use self::error::{TestError, TestErrorKind}; - - let kind = TestErrorKind::TestErrorKindB; - assert_eq!(String::from("testerrorkind B"), format!("{}", kind)); - - let e = TestError::new(kind, None); - assert_eq!(String::from("[testerrorkind B]"), format!("{}", e)); - - } - - #[test] - fn test_ab() { - use std::error::Error; - use self::error::{TestError, TestErrorKind}; - - let kinda = TestErrorKind::TestErrorKindA; - let kindb = TestErrorKind::TestErrorKindB; - assert_eq!(String::from("testerrorkind a"), format!("{}", kinda)); - assert_eq!(String::from("testerrorkind B"), format!("{}", kindb)); - - let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None)))); - assert_eq!(String::from("[testerrorkind a]"), format!("{}", e)); - assert_eq!(TestErrorKind::TestErrorKindA, e.err_type()); - assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap())); - } + generate_error_types!(TestError, TestErrorKind, + TestErrorKindA => "testerrorkind a", + TestErrorKindB => "testerrorkind B"); pub mod anothererrormod { - generate_error_imports!(); generate_error_types!(TestError, TestErrorKind, TestErrorKindA => "testerrorkind a", TestErrorKindB => "testerrorkind B"); } #[test] - fn test_other_a() { - use self::anothererrormod::{TestError, TestErrorKind}; - - let kind = TestErrorKind::TestErrorKindA; - assert_eq!(String::from("testerrorkind a"), format!("{}", kind)); - - let e = TestError::new(kind, None); - assert_eq!(String::from("[testerrorkind a]"), format!("{}", e)); - } - - #[test] - fn test_other_b() { - use self::anothererrormod::{TestError, TestErrorKind}; - - let kind = TestErrorKind::TestErrorKindB; - assert_eq!(String::from("testerrorkind B"), format!("{}", kind)); - - let e = TestError::new(kind, None); - assert_eq!(String::from("[testerrorkind B]"), format!("{}", e)); - - } - - #[test] - fn test_other_ab() { - use std::error::Error; - use self::anothererrormod::{TestError, TestErrorKind}; - - let kinda = TestErrorKind::TestErrorKindA; - let kindb = TestErrorKind::TestErrorKindB; - assert_eq!(String::from("testerrorkind a"), format!("{}", kinda)); - assert_eq!(String::from("testerrorkind B"), format!("{}", kindb)); - - let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None)))); - assert_eq!(String::from("[testerrorkind a]"), format!("{}", e)); - assert_eq!(TestErrorKind::TestErrorKindA, e.err_type()); - assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap())); - } - - #[test] fn test_error_kind_mapping() { - use std::io::{Error, ErrorKind}; - use self::error::MapErrInto; - use self::error::TestErrorKind; + use self::MapErrInto; + use self::TestErrorKind; - let err : Result<(), _> = Err(Error::new(ErrorKind::Other, "")); - let err : Result<(), _> = err.map_err_into(TestErrorKind::TestErrorKindA); + let err : Result<()> = Err(TestError::from_kind(TestErrorKind::TestErrorKindB)); + let err : Result<()> = err.map_err_into(TestErrorKind::TestErrorKindA); assert!(err.is_err()); - let err = err.unwrap_err(); - match err.err_type() { + match *err.unwrap_err().kind() { TestErrorKind::TestErrorKindA => assert!(true), _ => assert!(false), } @@ -390,17 +157,16 @@ mod test { #[test] fn test_error_kind_double_mapping() { - use std::io::{Error, ErrorKind}; - use self::error::MapErrInto; - use self::error::TestErrorKind; + use self::TestErrorKind; + use std::error::Error; - let err : Result<(), _> = Err(Error::new(ErrorKind::Other, "")); - let err : Result<(), _> = err.map_err_into(TestErrorKind::TestErrorKindA) + let err : Result<()> = Err(TestError::from_kind(TestErrorKind::TestErrorKindB)); + let err : Result<()> = err.map_err_into(TestErrorKind::TestErrorKindA) .map_err_into(TestErrorKind::TestErrorKindB); assert!(err.is_err()); let err = err.unwrap_err(); - match err.err_type() { + match *err.kind() { TestErrorKind::TestErrorKindB => assert!(true), _ => assert!(false), } @@ -415,8 +181,8 @@ mod test { #[test] fn test_error_option_good() { - use self::error::OkOrErr; - use self::error::TestErrorKind; + use self::OkOrErr; + use self::TestErrorKind; let something = Some(1); match something.ok_or_errkind(TestErrorKind::TestErrorKindA) { @@ -427,8 +193,8 @@ mod test { #[test] fn test_error_option_bad() { - use self::error::OkOrErr; - use self::error::TestErrorKind; + use self::OkOrErr; + use self::TestErrorKind; let something : Option<i32> = None; match something.ok_or_errkind(TestErrorKind::TestErrorKindA) { diff --git a/lib/core/libimagerror/src/lib.rs b/lib/core/libimagerror/src/lib.rs index 0ed1e7f3..f9aa7f98 100644 --- a/lib/core/libimagerror/src/lib.rs +++ b/lib/core/libimagerror/src/lib.rs @@ -36,6 +36,9 @@ #[macro_use] extern crate log; extern crate ansi_term; +#[cfg(test)] +#[macro_use] extern crate error_chain; + pub mod into; pub mod error_gen; pub mod trace; diff --git a/lib/core/libimagrt/src/configuration.rs b/lib/core/libimagrt/src/configuration.rs index bc3b52b4..4e064c02 100644 --- a/lib/core/libimagrt/src/configuration.rs +++ b/lib/core/libimagrt/src/configuration.rs @@ -24,24 +24,42 @@ use std::ops::Deref; use toml::Value; use clap::App; -generate_error_module!( - generate_error_types!(ConfigError, ConfigErrorKind, - TOMLParserError => "TOML Parsing error", - NoConfigFileFound => "No config file found", +error_chain! { + types { + ConfigError, ConfigErrorKind, ResultExt, Result; + } + + errors { + TOMLParserError { + description("TOML Parsing error") + display("TOML Parsing error") + } + + NoConfigFileFound { + description("No config file found") + display("No config file found") + } + + ConfigOverrideError { + description("Config override error") + display("Config override error") + } - ConfigOverrideError => "Config override error", - ConfigOverrideKeyNotAvailable => "Key not available", - ConfigOverrideTypeNotMatching => "Configuration Type not matching" + ConfigOverrideKeyNotAvailable { + description("Key not available") + display("Key not available") + } - ); -); + ConfigOverrideTypeNotMatching { + description("Configuration Type not matching") + display("Configuration Type not matching") + } + } +} pub use self::error::{ConfigError, ConfigErrorKind, MapErrInto}; use libimagerror::into::IntoError; -/// Result type of this module. Either `T` or `ConfigError` -pub type Result<T> = RResult<T, ConfigError>; - /// `Configuration` object /// /// Holds all config variables which are globally available plus the configuration object from the diff --git a/lib/core/libimagstore/src/error.rs b/lib/core/libimagstore/src/error.rs index 00e47681..8bba587f 100644 --- a/lib/core/libimagstore/src/error.rs +++ b/lib/core/libimagstore/src/error.rs @@ -17,99 +17,278 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // -generate_error_imports!(); -use std::convert::From; +error_chain! { + types { + StoreError, StoreErrorKind, ResultExt, Result; + } -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)] -pub struct CustomErrorData {} + errors { -impl Display for CustomErrorData { - fn fmt(&self, _: &mut Formatter) -> Result<(), FmtError> { - Ok(()) // Do nothing here, we don't need to print smth - } -} + ConfigurationError { + description("Store Configuration Error") + display("Store Configuration Error") + } -generate_custom_error_types!(StoreError, StoreErrorKind, CustomErrorData, - ConfigurationError => "Store Configuration Error", - ConfigTypeError => "Store configuration type error", - ConfigKeyMissingError => "Configuration Key missing", - - VersionError => "Incompatible store versions detected", - - CreateStoreDirDenied => "Creating store directory implicitely denied", - FileError => "File Error", - IoError => "IO Error", - IdLocked => "ID locked", - IdNotFound => "ID not found", - OutOfMemory => "Out of Memory", - FileNotFound => "File corresponding to ID not found", - FileNotCreated => "File corresponding to ID could not be created", - FileNotWritten => "File corresponding to ID could not be written to", - FileNotSeeked => "File corresponding to ID could not be seeked", - FileNotRemoved => "File corresponding to ID could not be removed", - FileNotRenamed => "File corresponding to ID could not be renamed", - FileNotCopied => "File could not be copied", - DirNotCreated => "Directory/Directories could not be created", - StorePathExists => "Store path exists", - StorePathCreate => "Store path create", - LockError => "Error locking datastructure", - LockPoisoned => "The internal Store Lock has been poisoned", - EntryAlreadyBorrowed => "Entry is already borrowed", - EntryAlreadyExists => "Entry already exists", - MalformedEntry => "Entry has invalid formatting, missing header", - HeaderPathSyntaxError => "Syntax error in accessor string", - HeaderPathTypeFailure => "Header has wrong type for path", - HeaderKeyNotFound => "Header Key not found", - HeaderTypeFailure => "Header type is wrong", - StorePathLacksVersion => "The supplied store path has no version part", - GlobError => "glob() error", - EncodingError => "Encoding error", - StorePathError => "Store Path error", - EntryRenameError => "Entry rename error", - StoreIdHandlingError => "StoreId handling error", - StoreIdLocalPartAbsoluteError => "StoreId 'id' part is absolute (starts with '/') which is not allowed", - StoreIdBuildFromFullPathError => "Building StoreId from full file path failed", - StoreIdHasNoBaseError => "StoreId has no 'base' part", - - CreateCallError => "Error when calling create()", - RetrieveCallError => "Error when calling retrieve()", - GetCallError => "Error when calling get()", - GetAllVersionsCallError => "Error when calling get_all_versions()", - RetrieveForModuleCallError => "Error when calling retrieve_for_module()", - UpdateCallError => "Error when calling update()", - RetrieveCopyCallError => "Error when calling retrieve_copy()", - DeleteCallError => "Error when calling delete()", - MoveCallError => "Error when calling move()", - MoveByIdCallError => "Error when calling move_by_id()" -); - -generate_result_helper!(StoreError, StoreErrorKind); -generate_option_helper!(StoreError, StoreErrorKind); - -generate_custom_error_types!(ParserError, ParserErrorKind, CustomErrorData, - TOMLParserErrors => "Several TOML-Parser-Errors", - MissingMainSection => "Missing main section", - MissingVersionInfo => "Missing version information in main section", - NonTableInBaseTable => "A non-table was found in the base table", - HeaderInconsistency => "The header is inconsistent" -); - -impl From<ParserError> for StoreError { - fn from(ps: ParserError) -> StoreError { - StoreError { - err_type: StoreErrorKind::MalformedEntry, - cause: Some(Box::new(ps)), - custom_data: None, + ConfigTypeError { + description("Store configuration type error") + display("Store configuration type error") + } + + ConfigKeyMissingError { + description("Configuration Key missing") + display("Configuration Key missing") + } + + VersionError { + description("Incompatible store versions detected") + display("Incompatible store versions detected") + } + + CreateStoreDirDenied { + description("Creating store directory implicitely denied") + display("Creating store directory implicitely denied") + } + + FileError { + description("File Error") + display("File Error") + } + + IoError { + description("IO Error") + display("IO Error") + } + + IdLocked { + description("ID locked") + display("ID locked") + } + + IdNotFound { + description("ID not found") + display("ID not found") + } + + OutOfMemory { + description("Out of Memory") + display("Out of Memory") + } + + FileNotFound { + description("File corresponding to ID not found") + display("File corresponding to ID not found") + } + + FileNotCreated { + description("File corresponding to ID could not be created") + display("File corresponding to ID could not be created") + } + + FileNotWritten { + description("File corresponding to ID could not be written to") + display("File corresponding to ID could not be written to") + } + + FileNotSeeked { + description("File corresponding to ID could not be seeked") + display("File corresponding to ID could not be seeked") + } + + FileNotRemoved { + description("File corresponding to ID could not be removed") + display("File corresponding to ID could not be removed") + } + + FileNotRenamed { + description("File corresponding to ID could not be renamed") + display("File corresponding to ID could not be renamed") + } + + FileNotCopied { + description("File could not be copied") + display("File could not be copied") + } + + DirNotCreated { + description("Directory/Directories could not be created") + display("Directory/Directories could not be created") + } + + StorePathExists { + description("Store path exists") + display("Store path exists") + } + + StorePathCreate { + description("Store path create") + display("Store path create") + } + + LockError { + description("Error locking datastructure") + display("Error locking datastructure") + } + + LockPoisoned { + description("The internal Store Lock has been poisoned") + display("The internal Store Lock has been poisoned") + } + + EntryAlreadyBorrowed { + description("Entry is already borrowed") + display("Entry is already borrowed") + } + + EntryAlreadyExists { + description("Entry already exists") + display("Entry already exists") + } + + MalformedEntry { + description("Entry has invalid formatting, missing header") + display("Entry has invalid formatting, missing header") + } + + HeaderPathSyntaxError { + description("Syntax error in accessor string") + display("Syntax error in accessor string") + } + + HeaderPathTypeFailure { + description("Header has wrong type for path") + display("Header has wrong type for path") + } + + HeaderKeyNotFound { + description("Header Key not found") + display("Header Key not found") + } + + HeaderTypeFailure { + description("Header type is wrong") + display("Header type is wrong") + } + + StorePathLacksVersion { + description("The supplied store path has no version part") + display("The supplied store path has no version part") + } + + GlobError { + description("glob() error") + display("glob() error") + } + + EncodingError { + description("Encoding error") + display("Encoding error") + } + + StorePathError { + description("Store Path error") + display("Store Path error") + } + + EntryRenameError { + description("Entry rename error") + display("Entry rename error") + } + + StoreIdHandlingError { + description("StoreId handling error") + display("StoreId handling error") + } + + StoreIdLocalPartAbsoluteError { + description("StoreId 'id' part is absolute (starts with '/') which is not allowed") + display("StoreId 'id' part is absolute (starts with '/') which is not allowed") + } + + StoreIdBuildFromFullPathError { + description("Building StoreId from full file path failed") + display("Building StoreId from full file path failed") + } + + StoreIdHasNoBaseError { + description("StoreId has no 'base' part") + display("StoreId has no 'base' part") + } + |