errer/
lib.rs

1/// A simple yet flexible crate for error management
2/// 
3/// a lot of these ideas are stolen from SNAFU
4/// but i wanted to make a more flexible version that works with all kinds of errors
5
6#[cfg(feature = "print-error")]
7extern crate termcolor;
8
9#[cfg(feature = "print-error")]
10use std::io;
11use std::fmt;
12use std::error::Error;
13#[cfg(feature = "print-error")]
14use std::io::Write;
15#[cfg(feature = "print-error")]
16use termcolor::{WriteColor, StandardStream, ColorSpec, Color};
17
18#[cfg(feature = "print-error")]
19/// A relatively simple utility trait for printing more complicated errors.
20pub trait PrintError {
21    fn print(&self, io: &mut StandardStream) -> io::Result<()>;
22}
23
24#[cfg(feature = "print-error")]
25impl<E: std::error::Error + ?Sized> PrintError for E {
26    fn print(&self, io: &mut StandardStream) -> io::Result<()> {
27        if let Some(cause) = self.source() {
28            cause.print(io)?;
29        }
30
31        io.set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
32        write!(io, "error: ")?;
33
34        io.set_color(ColorSpec::new().set_fg(None))?;
35        writeln!(io, "{}", self)?;
36        
37        Ok(())
38    }
39}
40
41/// A compabitility trait that implements std::error::Error but only when Self implements Display + Debug
42pub trait ErrorCompat {
43    fn error_source(&self) -> Option<&(dyn Error + 'static)>;
44}
45
46trait CompatDisplayDebug: fmt::Display + fmt::Debug + ErrorCompat { }
47impl<T> CompatDisplayDebug for T where T: fmt::Display + fmt::Debug + ErrorCompat { }
48
49impl Error for dyn CompatDisplayDebug {
50    fn source(&self) -> Option<&(dyn Error + 'static)> {
51        self.error_source()
52    }
53}
54
55/// A trait that takes a context + self to produce a target.
56/// This is useful for errors that depend on a context, or when used to generate errors from a context and error (see: [`ErrorContext`]).
57/// 
58/// [`ErrorContext`]: ../trait.ErrorContext.html
59pub trait IntoErrorContext<Context, Target> {
60    fn into_target(self, ctx: Context) -> Target;
61}
62
63/// Reverse implemented for Result<T, E> where E: [`IntoErrorContext`]
64/// 
65/// [`IntoErrorContext`]: ../trait.IntoErrorContext.html
66pub trait ErrorContext<Context, Target> {
67    fn context(self, ctx: Context) -> Target;
68    fn context_with<F: Fn() -> Context>(self, ctx: F) -> Target;
69}
70
71//impl errorcontext<io::Error, Error> for ErrorKind
72//produces errorcontext<ErrorKind, Error> for io::Error
73impl<Context, Target, T, E: IntoErrorContext<Context, Target>> ErrorContext<E, Result<T, Target>> for Result<T, Context>  {
74    fn context(self, ctx: E) -> Result<T, Target> {
75        self.map_err(|x| ctx.into_target(x))
76    }
77
78    fn context_with<F: Fn() -> E>(self, ctx: F) -> Result<T, Target> {
79        self.map_err(|x| ctx().into_target(x))
80    }
81}
82
83//Generate a main function for a function that returns a result. Good for quick setups/examples
84#[macro_export]
85macro_rules! main_res {
86    ($main: ident) => {
87        fn main() {
88            if let Err(err) = $main() {
89                println!("{}", err);
90            }
91        }
92    };
93}
94
95//Generate a Result type (conviently named "Res") for your error
96#[macro_export]
97macro_rules! res {
98    ($err: ident) => {
99        type Res<T> = Result<T, $err>;
100    };
101    ($err: ident < $($arg: tt),* >) => {
102        type Res<$($arg),*, T> = Result<T, $err<$($arg),*>>;
103    };
104}