errer 0.13.0

Flexible error management for Rust. An middle-ground between failure and SNAFU
Documentation
/// A simple yet flexible crate for error management
/// 
/// a lot of these ideas are stolen from SNAFU
/// but i wanted to make a more flexible version that works with all kinds of errors

#[cfg(feature = "print-error")]
extern crate termcolor;

#[cfg(feature = "print-error")]
use std::io;
use std::fmt;
use std::error::Error;
#[cfg(feature = "print-error")]
use std::io::Write;
#[cfg(feature = "print-error")]
use termcolor::{WriteColor, StandardStream, ColorSpec, Color};

#[cfg(feature = "print-error")]
/// A relatively simple utility trait for printing more complicated errors.
pub trait PrintError {
    fn print(&self, io: &mut StandardStream) -> io::Result<()>;
}

#[cfg(feature = "print-error")]
impl<E: std::error::Error + ?Sized> PrintError for E {
    fn print(&self, io: &mut StandardStream) -> io::Result<()> {
        if let Some(cause) = self.source() {
            cause.print(io)?;
        }

        io.set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
        write!(io, "error: ")?;

        io.set_color(ColorSpec::new().set_fg(None))?;
        writeln!(io, "{}", self)?;
        
        Ok(())
    }
}

/// A compabitility trait that implements std::error::Error but only when Self implements Display + Debug
pub trait ErrorCompat {
    fn error_source(&self) -> Option<&(dyn Error + 'static)>;
}

trait CompatDisplayDebug: fmt::Display + fmt::Debug + ErrorCompat { }
impl<T> CompatDisplayDebug for T where T: fmt::Display + fmt::Debug + ErrorCompat { }

impl Error for dyn CompatDisplayDebug {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        self.error_source()
    }
}

/// A trait that takes a context + self to produce a target.
/// This is useful for errors that depend on a context, or when used to generate errors from a context and error (see: [`ErrorContext`]).
/// 
/// [`ErrorContext`]: ../trait.ErrorContext.html
pub trait IntoErrorContext<Context, Target> {
    fn into_target(self, ctx: Context) -> Target;
}

/// Reverse implemented for Result<T, E> where E: [`IntoErrorContext`]
/// 
/// [`IntoErrorContext`]: ../trait.IntoErrorContext.html
pub trait ErrorContext<Context, Target> {
    fn context(self, ctx: Context) -> Target;
    fn context_with<F: Fn() -> Context>(self, ctx: F) -> Target;
}

//impl errorcontext<io::Error, Error> for ErrorKind
//produces errorcontext<ErrorKind, Error> for io::Error
impl<Context, Target, T, E: IntoErrorContext<Context, Target>> ErrorContext<E, Result<T, Target>> for Result<T, Context>  {
    fn context(self, ctx: E) -> Result<T, Target> {
        self.map_err(|x| ctx.into_target(x))
    }

    fn context_with<F: Fn() -> E>(self, ctx: F) -> Result<T, Target> {
        self.map_err(|x| ctx().into_target(x))
    }
}

//Generate a main function for a function that returns a result. Good for quick setups/examples
#[macro_export]
macro_rules! main_res {
    ($main: ident) => {
        fn main() {
            if let Err(err) = $main() {
                println!("{}", err);
            }
        }
    };
}

//Generate a Result type (conviently named "Res") for your error
#[macro_export]
macro_rules! res {
    ($err: ident) => {
        type Res<T> = Result<T, $err>;
    };
    ($err: ident < $($arg: tt),* >) => {
        type Res<$($arg),*, T> = Result<T, $err<$($arg),*>>;
    };
}