mirror of
https://github.com/haraldh/chainerror.git
synced 2025-01-31 00:56:41 +01:00
refactor
This commit is contained in:
parent
6066a41f97
commit
8017b6cdfd
149
src/lib.rs
149
src/lib.rs
|
@ -1,25 +1,52 @@
|
||||||
pub trait ChainError: ::std::error::Error + Sized {
|
pub trait ChainError: ::std::error::Error + Sized {
|
||||||
fn root_cause(&self) -> Option<&(dyn::std::error::Error + 'static)>;
|
fn new(
|
||||||
|
line: u32,
|
||||||
|
filename: &'static str,
|
||||||
|
description: Option<String>,
|
||||||
|
error_cause: Option<Box<dyn std::error::Error + 'static>>,
|
||||||
|
) -> Self;
|
||||||
|
|
||||||
|
fn root_cause(&self) -> Option<&(dyn std::error::Error + 'static)>;
|
||||||
fn find_cause<T: ::std::error::Error + 'static>(
|
fn find_cause<T: ::std::error::Error + 'static>(
|
||||||
&self,
|
&self,
|
||||||
) -> Option<&(dyn::std::error::Error + 'static)>;
|
) -> Option<&(dyn std::error::Error + 'static)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ChainErrorFrom<T>: ChainError {
|
||||||
|
fn chain_error_from(_: T, _: u32, _: &'static str, _: Option<String>) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IntoChainError<T: ChainError>: Sized {
|
||||||
|
fn into_chain_error(self, line: u32, filename: &'static str, description: Option<String>) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> IntoChainError<U> for T
|
||||||
|
where
|
||||||
|
U: ChainErrorFrom<T> + ChainError,
|
||||||
|
{
|
||||||
|
fn into_chain_error(self, line: u32, filename: &'static str, description: Option<String>) -> U {
|
||||||
|
U::chain_error_from(self, line, filename, description)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! chain_error {
|
macro_rules! chain_error_fn {
|
||||||
( $t:ident, $v:expr $(, $more:expr)* ) => {
|
( $t:ident, $v:expr $(, $more:expr)* ) => {
|
||||||
|e| <$t> :: new(line!(), file!(), format!($v, $( $more , )* ), Some(e.into()))
|
|e| <$t> :: new(line!(), file!(), Some(format!($v, $( $more , )* )), Some(e.into()))
|
||||||
};
|
};
|
||||||
( $t:path, $v:expr $(, $more:expr)* ) => {
|
( $t:path, $v:expr $(, $more:expr)* ) => {
|
||||||
|e| <$t> :: new(line!(), file!(), format!($v, $( $more , )* ), Some(e.into()))
|
|e| <$t> :: new(line!(), file!(), Some(format!($v, $( $more , )* )), Some(e.into()))
|
||||||
|
};
|
||||||
|
( $t:ident) => {
|
||||||
|
|e| <$t> :: new(line!(), file!(), None, Some(e.into()))
|
||||||
|
};
|
||||||
|
( $t:path) => {
|
||||||
|
|e| <$t> :: new(line!(), file!(), None, Some(e.into()))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! into_chain_error {
|
macro_rules! into_chain_error_fn {
|
||||||
( $v:expr $(, $more:expr)* ) => {
|
|
||||||
|e| e.into_chain_error(line!(), file!(), Some(format!($v, $( $more , )* )))
|
|
||||||
};
|
|
||||||
( $v:expr $(, $more:expr)* ) => {
|
( $v:expr $(, $more:expr)* ) => {
|
||||||
|e| e.into_chain_error(line!(), file!(), Some(format!($v, $( $more , )* )))
|
|e| e.into_chain_error(line!(), file!(), Some(format!($v, $( $more , )* )))
|
||||||
};
|
};
|
||||||
|
@ -29,31 +56,52 @@ macro_rules! into_chain_error {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! throw_error {
|
macro_rules! chain_error_from_fn {
|
||||||
( $t:ident, $v:expr $(, $more:expr)* ) => {
|
( $t:expr, $v:expr $(, $more:expr)* ) => {
|
||||||
Err(<$t> :: new(line!(), file!(), format!($v, $( $more , )*), None))
|
|e| ($t).into().chain_error_from(e, line!(), file!(), Some(format!($v, $( $more , )* )))
|
||||||
};
|
};
|
||||||
( $t:path, $v:expr $(, $more:expr)* ) => {
|
|
||||||
Err(<$t> :: new(line!(), file!(), format!($v, $( $more , )*), None))
|
( $t:expr ) => {
|
||||||
|
|e| ($t).into().chain_error_from(e, line!(), file!(), None)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! new_chain_error {
|
macro_rules! chain_error {
|
||||||
|
( $t:ident, $v:expr $(, $more:expr)* ) => {
|
||||||
|
<$t> :: new(line!(), file!(), Some(format!($v, $( $more , )*)), None)
|
||||||
|
};
|
||||||
|
( $t:path, $v:expr $(, $more:expr)* ) => {
|
||||||
|
<$t> :: new(line!(), file!(), Some(format!($v, $( $more , )*)), None)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! into_chain_error {
|
||||||
|
( $t:expr, $v:expr $(, $more:expr)* ) => {
|
||||||
|
$t . into_chain_error(line!(), file!(), Some(format!($v, $( $more , )*)))
|
||||||
|
};
|
||||||
|
( $t:expr ) => {
|
||||||
|
$t . into_chain_error(line!(), file!(), None)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! derive_chain_error {
|
||||||
($e:ident) => {
|
($e:ident) => {
|
||||||
pub struct $e {
|
pub struct $e {
|
||||||
line: u32,
|
line: u32,
|
||||||
filename: &'static str,
|
filename: &'static str,
|
||||||
description: String,
|
description: Option<String>,
|
||||||
error_cause: Option<Box<dyn::std::error::Error + 'static>>,
|
error_cause: Option<Box<dyn std::error::Error + 'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $e {
|
impl ChainError for $e {
|
||||||
pub fn new(
|
fn new(
|
||||||
line: u32,
|
line: u32,
|
||||||
filename: &'static str,
|
filename: &'static str,
|
||||||
description: String,
|
description: Option<String>,
|
||||||
error_cause: Option<Box<dyn::std::error::Error + 'static>>,
|
error_cause: Option<Box<dyn std::error::Error + 'static>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
$e {
|
$e {
|
||||||
line,
|
line,
|
||||||
|
@ -62,11 +110,9 @@ macro_rules! new_chain_error {
|
||||||
error_cause,
|
error_cause,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl ChainError for $e {
|
fn root_cause(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
fn root_cause(&self) -> Option<&(dyn::std::error::Error + 'static)> {
|
let mut cause = self as &(dyn std::error::Error + 'static);
|
||||||
let mut cause = self as &(dyn::std::error::Error + 'static);
|
|
||||||
while let Some(c) = cause.source() {
|
while let Some(c) = cause.source() {
|
||||||
cause = c;
|
cause = c;
|
||||||
}
|
}
|
||||||
|
@ -75,8 +121,8 @@ macro_rules! new_chain_error {
|
||||||
|
|
||||||
fn find_cause<T: ::std::error::Error + 'static>(
|
fn find_cause<T: ::std::error::Error + 'static>(
|
||||||
&self,
|
&self,
|
||||||
) -> Option<&(dyn::std::error::Error + 'static)> {
|
) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
let mut cause = self as &(dyn::std::error::Error + 'static);
|
let mut cause = self as &(dyn std::error::Error + 'static);
|
||||||
loop {
|
loop {
|
||||||
if cause.is::<T>() {
|
if cause.is::<T>() {
|
||||||
return Some(cause);
|
return Some(cause);
|
||||||
|
@ -92,10 +138,14 @@ macro_rules! new_chain_error {
|
||||||
|
|
||||||
impl ::std::error::Error for $e {
|
impl ::std::error::Error for $e {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
&self.description
|
if let Some(ref d) = self.description {
|
||||||
|
d.as_ref()
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn source(&self) -> Option<&(dyn::std::error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
if let Some(ref e) = self.error_cause {
|
if let Some(ref e) = self.error_cause {
|
||||||
Some(e.as_ref())
|
Some(e.as_ref())
|
||||||
} else {
|
} else {
|
||||||
|
@ -106,7 +156,7 @@ macro_rules! new_chain_error {
|
||||||
|
|
||||||
impl ::std::fmt::Display for $e {
|
impl ::std::fmt::Display for $e {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
writeln!(f, "{}", self.description)?;
|
writeln!(f, "{}", self.description())?;
|
||||||
if let Some(e) = self.source() {
|
if let Some(e) = self.source() {
|
||||||
writeln!(f, "\nCaused by:")?;
|
writeln!(f, "\nCaused by:")?;
|
||||||
::std::fmt::Display::fmt(&e, f)?;
|
::std::fmt::Display::fmt(&e, f)?;
|
||||||
|
@ -117,7 +167,13 @@ macro_rules! new_chain_error {
|
||||||
|
|
||||||
impl ::std::fmt::Debug for $e {
|
impl ::std::fmt::Debug for $e {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
writeln!(f, "\n{}:{}: {}", self.filename, self.line, self.description)?;
|
writeln!(
|
||||||
|
f,
|
||||||
|
"\n{}:{}: {}",
|
||||||
|
self.filename,
|
||||||
|
self.line,
|
||||||
|
self.description()
|
||||||
|
)?;
|
||||||
if let Some(e) = self.source() {
|
if let Some(e) = self.source() {
|
||||||
writeln!(f, "\nCaused by:")?;
|
writeln!(f, "\nCaused by:")?;
|
||||||
::std::fmt::Debug::fmt(&e, f)?;
|
::std::fmt::Debug::fmt(&e, f)?;
|
||||||
|
@ -128,36 +184,25 @@ macro_rules! new_chain_error {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FromChainError<T>: Sized {
|
|
||||||
fn from_chain_error(_: T, _: u32, _: &'static str, _: Option<String>) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait IntoChainError<T>: Sized {
|
|
||||||
fn into_chain_error(self, line: u32, filename: &'static str, description: Option<String>) -> T;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, U> IntoChainError<U> for T where U: FromChainError<T>
|
|
||||||
{
|
|
||||||
fn into_chain_error(self, line: u32, filename: &'static str, description: Option<String>) -> U {
|
|
||||||
U::from_chain_error(self, line, filename, description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use super::{chain_error, new_chain_error, throw_error, ChainError};
|
pub use super::{
|
||||||
|
chain_error, chain_error_fn, chain_error_from_fn, derive_chain_error, into_chain_error,
|
||||||
|
into_chain_error_fn, ChainError, ChainErrorFrom, IntoChainError,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::prelude::*;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
new_chain_error!(MyError);
|
use crate::prelude::*;
|
||||||
new_chain_error!(MyMainError);
|
|
||||||
|
derive_chain_error!(MyError);
|
||||||
|
derive_chain_error!(MyMainError);
|
||||||
|
|
||||||
fn throw_error() -> Result<(), MyError> {
|
fn throw_error() -> Result<(), MyError> {
|
||||||
let directory = String::from("ldfhgdfkgjdf");
|
let directory = String::from("ldfhgdfkgjdf");
|
||||||
::std::fs::remove_dir(&directory).map_err(chain_error!(
|
::std::fs::remove_dir(&directory).map_err(chain_error_fn!(
|
||||||
MyError,
|
MyError,
|
||||||
"Could not remove directory '{}'{}",
|
"Could not remove directory '{}'{}",
|
||||||
&directory,
|
&directory,
|
||||||
|
@ -168,7 +213,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_works() -> Result<(), MyMainError> {
|
fn it_works() -> Result<(), MyMainError> {
|
||||||
let res = throw_error().map_err(chain_error!(MyMainError, "I has an error."));
|
let res = throw_error().map_err(chain_error_fn!(MyMainError, "I has an error."));
|
||||||
|
|
||||||
if let Err(my_err) = res {
|
if let Err(my_err) = res {
|
||||||
if let Some(source) = my_err.source() {
|
if let Some(source) = my_err.source() {
|
||||||
|
|
Loading…
Reference in a new issue