chainerror/src/lib.rs

288 lines
7.6 KiB
Rust
Raw Normal View History

2018-12-19 16:30:56 +01:00
use std::error::Error;
use std::fmt::{Debug, Display, Formatter, Result};
2018-12-20 10:08:54 +01:00
use std::result::Result as StdResult;
2018-12-19 16:30:56 +01:00
pub struct ChainError<T> {
#[cfg(feature = "fileline")]
occurrence: Option<(u32, &'static str)>,
kind: T,
error_cause: Option<Box<dyn Error + 'static>>,
2018-12-18 16:21:45 +01:00
}
2018-12-20 10:08:54 +01:00
pub type ChainResult<O, E> = StdResult<O, ChainError<E>>;
2018-12-19 16:30:56 +01:00
impl<T: 'static + Display + Debug> ChainError<T> {
#[cfg(feature = "fileline")]
pub fn new(
kind: T,
error_cause: Option<Box<dyn Error + 'static>>,
occurrence: Option<(u32, &'static str)>,
) -> Self {
Self {
occurrence,
kind,
error_cause,
}
}
2018-12-18 16:21:45 +01:00
2018-12-19 16:30:56 +01:00
#[cfg(not(feature = "fileline"))]
pub fn new(
kind: T,
error_cause: Option<Box<dyn Error + 'static>>,
_occurrence: Option<(u32, &'static str)>,
) -> Self {
Self { kind, error_cause }
}
pub fn root_cause(&self) -> Option<&(dyn Error + 'static)> {
let mut cause = self as &(dyn Error + 'static);
while let Some(c) = cause.source() {
cause = c;
}
Some(cause)
}
2018-12-20 10:08:54 +01:00
pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> {
2018-12-19 16:30:56 +01:00
let mut cause = self as &(dyn Error + 'static);
loop {
if cause.is::<U>() {
2018-12-20 10:08:54 +01:00
return cause.downcast_ref::<U>();
2018-12-19 16:30:56 +01:00
}
match cause.source() {
Some(c) => cause = c,
None => return None,
}
}
}
2018-12-20 10:08:54 +01:00
pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> {
2018-12-19 16:30:56 +01:00
let mut cause = self as &(dyn Error + 'static);
loop {
if cause.is::<ChainError<U>>() {
return cause.downcast_ref::<ChainError<U>>();
}
match cause.source() {
Some(c) => cause = c,
None => return None,
}
}
}
2018-12-18 16:21:45 +01:00
2018-12-19 16:30:56 +01:00
pub fn kind<'a>(&'a self) -> &'a T {
&self.kind
2018-12-18 16:21:45 +01:00
}
2018-12-18 07:46:05 +01:00
}
2018-12-19 16:30:56 +01:00
pub trait ChainErrorDown {
fn is_chain<T: 'static + Display + Debug>(&self) -> bool;
fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>>;
fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>>;
2018-12-18 07:46:05 +01:00
}
2018-12-19 16:30:56 +01:00
use std::any::TypeId;
impl<U: 'static + Display + Debug> ChainErrorDown for ChainError<U> {
fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
TypeId::of::<T>() == TypeId::of::<U>()
}
fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
if self.is_chain::<T>() {
unsafe { Some(&*(self as *const dyn Error as *const &ChainError<T>)) }
} else {
None
}
}
fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
if self.is_chain::<T>() {
unsafe { Some(&mut *(self as *mut dyn Error as *mut &mut ChainError<T>)) }
} else {
None
}
}
2018-12-18 19:04:02 +01:00
}
2018-12-19 16:30:56 +01:00
impl ChainErrorDown for dyn Error + 'static {
fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
self.is::<ChainError<T>>()
}
fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
self.downcast_ref::<ChainError<T>>()
}
fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
self.downcast_mut::<ChainError<T>>()
}
2018-12-18 19:04:02 +01:00
}
2018-12-19 16:30:56 +01:00
impl ChainErrorDown for dyn Error + 'static + Send {
fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
self.is::<ChainError<T>>()
}
fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
self.downcast_ref::<ChainError<T>>()
}
fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
self.downcast_mut::<ChainError<T>>()
}
2018-12-18 07:46:05 +01:00
}
2018-12-19 16:30:56 +01:00
impl ChainErrorDown for dyn Error + 'static + Send + Sync {
fn is_chain<T: 'static + Display + Debug>(&self) -> bool {
self.is::<ChainError<T>>()
}
2018-12-18 16:21:45 +01:00
2018-12-19 16:30:56 +01:00
fn downcast_chain_ref<T: 'static + Display + Debug>(&self) -> Option<&ChainError<T>> {
self.downcast_ref::<ChainError<T>>()
}
fn downcast_chain_mut<T: 'static + Display + Debug>(&mut self) -> Option<&mut ChainError<T>> {
self.downcast_mut::<ChainError<T>>()
}
2018-12-18 16:21:45 +01:00
}
2018-12-19 16:30:56 +01:00
impl<T: 'static + Display + Debug> Error for ChainError<T> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
if let Some(ref e) = self.error_cause {
Some(e.as_ref())
} else {
None
}
}
2018-12-18 07:46:05 +01:00
}
2018-12-19 16:30:56 +01:00
impl<T: 'static + Display + Debug> Error for &ChainError<T> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
if let Some(ref e) = self.error_cause {
Some(e.as_ref())
} else {
None
}
}
2018-12-18 16:21:45 +01:00
}
2018-12-19 16:30:56 +01:00
impl<T: 'static + Display + Debug> Error for &mut ChainError<T> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
if let Some(ref e) = self.error_cause {
Some(e.as_ref())
} else {
None
2018-12-18 07:46:05 +01:00
}
2018-12-19 16:30:56 +01:00
}
}
2018-12-18 07:46:05 +01:00
2018-12-19 16:30:56 +01:00
impl<T: 'static + Display + Debug> Display for ChainError<T> {
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "{}", self.kind)?;
2018-12-18 07:46:05 +01:00
2018-12-19 16:30:56 +01:00
#[cfg(feature = "display-cause")]
{
if let Some(e) = self.source() {
writeln!(f, "\nCaused by:")?;
Display::fmt(&e, f)?;
2018-12-18 07:46:05 +01:00
}
2018-12-19 16:30:56 +01:00
}
Ok(())
}
}
2018-12-18 07:46:05 +01:00
2018-12-19 16:30:56 +01:00
impl<T: 'static + Display + Debug> Debug for ChainError<T> {
fn fmt(&self, f: &mut Formatter) -> Result {
#[cfg(feature = "fileline")]
{
if let Some(o) = self.occurrence {
write!(f, "{}:{}: ", o.1, o.0)?;
2018-12-18 07:46:05 +01:00
}
}
2018-12-19 16:30:56 +01:00
Debug::fmt(&self.kind, f)?;
2018-12-18 07:46:05 +01:00
2018-12-19 16:30:56 +01:00
#[cfg(feature = "debug-cause")]
{
if let Some(e) = self.source() {
writeln!(f, "\nCaused by:")?;
Debug::fmt(&e, f)?;
2018-12-18 07:46:05 +01:00
}
}
2018-12-19 16:30:56 +01:00
Ok(())
}
}
2018-12-18 07:46:05 +01:00
2018-12-19 16:30:56 +01:00
#[macro_export]
macro_rules! cherr {
( $k:expr ) => {
ChainError::<_>::new($k, None, Some((line!(), file!())))
};
( $e:expr, $k:expr ) => {
ChainError::<_>::new($k, Some(Box::from($e)), Some((line!(), file!())))
};
}
#[macro_export]
macro_rules! mstrerr {
( $t:ident, $v:expr $(, $more:expr)* ) => {
|e| cherr!(e, $t (format!($v, $( $more , )* )))
};
( $t:path, $v:expr $(, $more:expr)* ) => {
|e| cherr!(e, $t (format!($v, $( $more , )* )))
};
2018-12-20 10:08:54 +01:00
( $v:expr $(, $more:expr)* ) => {
|e| cherr!(e, format!($v, $( $more , )* ))
};
2018-12-19 16:30:56 +01:00
}
#[macro_export]
macro_rules! derive_str_cherr {
($e:ident) => {
struct $e(String);
2018-12-18 07:46:05 +01:00
impl ::std::fmt::Display for $e {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
2018-12-19 16:30:56 +01:00
write!(f, "{}", self.0)
2018-12-18 07:46:05 +01:00
}
}
impl ::std::fmt::Debug for $e {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
2018-12-19 16:30:56 +01:00
write!(f, "{}({})", stringify!($e), self.0)
2018-12-18 07:46:05 +01:00
}
}
2018-12-20 10:08:54 +01:00
impl ::std::error::Error for $e {}
};
}
#[macro_export]
macro_rules! try_cherr_ref {
( $e:expr, $t:ident ) => {
$e.downcast_ref::<ChainError<$t>>()
};
( $e:expr, $t:path ) => {
$e.downcast_ref::<ChainError<$t>>()
};
}
#[macro_export]
macro_rules! try_cherr_mut {
( $e:expr, $t:ident ) => {
$e.downcast_mut::<ChainError<$t>>()
};
( $e:expr, $t:path ) => {
$e.downcast_mut::<ChainError<$t>>()
2018-12-18 07:46:05 +01:00
};
}
pub mod prelude {
2018-12-20 10:08:54 +01:00
pub use super::{
cherr, derive_str_cherr, mstrerr, try_cherr_mut, try_cherr_ref, ChainError, ChainErrorDown,
ChainResult,
};
2018-12-18 07:46:05 +01:00
}
#[cfg(test)]
mod tests {
}