2016-05-16 21:51:26 +00:00
|
|
|
use into::IntoError;
|
|
|
|
|
2016-05-19 14:58:42 +00:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! generate_error_imports {
|
|
|
|
() => {
|
|
|
|
use std::error::Error;
|
|
|
|
use std::fmt::Error as FmtError;
|
|
|
|
use std::fmt::{Display, Formatter};
|
2016-05-20 15:11:51 +00:00
|
|
|
|
|
|
|
use $crate::into::IntoError;
|
2016-05-19 14:58:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! generate_error_module {
|
|
|
|
( $exprs:item ) => {
|
|
|
|
pub mod error {
|
|
|
|
generate_error_imports!();
|
|
|
|
$exprs
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-15 14:00:51 +00:00
|
|
|
#[macro_export]
|
2016-05-16 22:14:00 +00:00
|
|
|
macro_rules! generate_custom_error_types {
|
|
|
|
{
|
2016-05-15 14:00:51 +00:00
|
|
|
$name: ident,
|
|
|
|
$kindname: ident,
|
2016-05-16 22:14:00 +00:00
|
|
|
$customMemberTypeName: ident,
|
2016-05-15 14:00:51 +00:00
|
|
|
$($kind:ident => $string:expr),*
|
2016-05-16 22:14:00 +00:00
|
|
|
} => {
|
2016-05-15 14:00:51 +00:00
|
|
|
#[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(())
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-05-16 21:51:26 +00:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-05-15 14:00:51 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct $name {
|
|
|
|
err_type: $kindname,
|
|
|
|
cause: Option<Box<Error>>,
|
2016-05-16 22:14:00 +00:00
|
|
|
custom_data: Option<$customMemberTypeName>,
|
2016-05-15 14:00:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl $name {
|
|
|
|
|
|
|
|
pub fn new(errtype: $kindname, cause: Option<Box<Error>>) -> $name {
|
|
|
|
$name {
|
|
|
|
err_type: errtype,
|
|
|
|
cause: cause,
|
2016-05-16 22:14:00 +00:00
|
|
|
custom_data: None,
|
2016-05-15 14:00:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn err_type(&self) -> $kindname {
|
|
|
|
self.err_type
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for $name {
|
|
|
|
|
|
|
|
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
|
|
|
|
try!(write!(fmt, "[{}]", self.err_type));
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Error for $name {
|
|
|
|
|
|
|
|
fn description(&self) -> &str {
|
|
|
|
match self.err_type {
|
|
|
|
$( $kindname::$kind => $string ),*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn cause(&self) -> Option<&Error> {
|
|
|
|
self.cause.as_ref().map(|e| &**e)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-16 22:14:00 +00:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! generate_error_types {
|
|
|
|
(
|
|
|
|
$name: ident,
|
|
|
|
$kindname: ident,
|
|
|
|
$($kind:ident => $string:expr),*
|
|
|
|
) => {
|
2016-05-16 22:14:10 +00:00
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
|
|
|
|
pub struct SomeNotExistingTypeWithATypeNameNoOneWillEverChoose {}
|
|
|
|
generate_custom_error_types!($name, $kindname,
|
|
|
|
SomeNotExistingTypeWithATypeNameNoOneWillEverChoose,
|
|
|
|
$($kind => $string),*);
|
2016-05-16 22:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-15 14:00:51 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
|
2016-05-19 14:58:42 +00:00
|
|
|
generate_error_module!(
|
|
|
|
generate_error_types!(TestError, TestErrorKind,
|
|
|
|
TestErrorKindA => "testerrorkind a",
|
|
|
|
TestErrorKindB => "testerrorkind B");
|
|
|
|
);
|
2016-05-15 14:00:51 +00:00
|
|
|
|
2016-05-16 22:14:10 +00:00
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
|
|
|
|
pub struct CustomData {
|
|
|
|
pub test: i32,
|
|
|
|
pub othr: i64,
|
|
|
|
}
|
|
|
|
|
|
|
|
generate_error_imports!();
|
|
|
|
|
|
|
|
generate_custom_error_types!(CustomTestError, CustomTestErrorKind,
|
|
|
|
CustomData,
|
|
|
|
CustomErrorKindA => "customerrorkind a",
|
|
|
|
CustomErrorKindB => "customerrorkind B");
|
|
|
|
|
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-15 14:00:51 +00:00
|
|
|
#[test]
|
|
|
|
fn test_a() {
|
2016-05-19 14:58:42 +00:00
|
|
|
use self::error::{TestError, TestErrorKind};
|
|
|
|
|
2016-05-15 14:00:51 +00:00
|
|
|
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() {
|
2016-05-19 14:58:42 +00:00
|
|
|
use self::error::{TestError, TestErrorKind};
|
|
|
|
|
2016-05-15 14:00:51 +00:00
|
|
|
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() {
|
2016-05-19 14:58:42 +00:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
|
|
|
|
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};
|
|
|
|
|
2016-05-15 14:00:51 +00:00
|
|
|
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()));
|
|
|
|
}
|
|
|
|
}
|