#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]
extern crate typeable;
extern crate traitobject;
use std::fmt::Debug;
use std::any::TypeId;
use std::error::Error as StdError;
use std::mem;
use typeable::Typeable;
pub trait Error: Debug + Send + Typeable + StdError { }
impl<S: StdError + Debug + Send + Typeable> Error for S { }
impl Error {
pub fn is<E: Error>(&self) -> bool { self.get_type() == TypeId::of::<E>() }
pub fn downcast<E: Error>(&self) -> Option<&E> {
if self.is::<E>() {
unsafe { Some(mem::transmute(traitobject::data(self))) }
} else {
None
}
}
}
impl Error + Send {
pub fn is<E: Error + Send>(&self) -> bool { self.get_type() == TypeId::of::<E>() }
pub fn downcast<E: Error + Send>(&self) -> Option<&E> {
if self.is::<E>() {
unsafe { Some(mem::transmute(traitobject::data(self))) }
} else {
None
}
}
}
impl<E: Error> From<E> for Box<Error> {
fn from(e: E) -> Box<Error> { Box::new(e) }
}
#[macro_export]
macro_rules! match_error {
($m:expr, $i1:pat => $t1:ty: $e1:expr) => {{
let tmp = $m;
match tmp.downcast::<$t1>() {
Some($i1) => Some($e1),
None => None,
}
}};
($m:expr, $i1:pat => $t1:ty: $e1:expr, $($i:pat => $t:ty: $e:expr),+) => {{
let tmp = $m;
match tmp.downcast::<$t1>() {
Some($i1) => Some($e1),
None => match_error!(tmp, $($i: $t => $e),*),
}
}};
}
#[cfg(test)]
mod test {
use super::Error;
use std::error::Error as StdError;
use std::fmt::Error as FmtError;
use std::fmt::Display;
use std::fmt::Formatter;
#[derive(Debug, PartialEq)]
pub struct ParseError {
location: usize,
}
impl StdError for ParseError {
fn description(&self) -> &str { "Parse Error" }
}
impl Display for ParseError {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
self.description().fmt(f)
}
}
#[test] fn test_generic() {
fn produce_parse_error() -> Box<Error> {
Box::new(ParseError { location: 7 })
}
fn generic_handler(raw: Box<Error>) {
(match_error! { raw,
parse => ParseError: {
assert_eq!(*parse, ParseError { location: 7 })
}
}).unwrap()
}
generic_handler(produce_parse_error())
}
}