dynerr 0.1.24

Macros for dynamic error handling
Documentation
# dynerr


Some macros to help with dynamic error handling/logging.\
The goal of this crate is to unify all error types without compromising type safety.\
\
The main features of this crate are the `dynerr!` and `dynmatch!` macros. when used alongside the return type `DynResult<T>`, they allows you to return multiple error types from a function then easily match for them during your error handling. Using dynerr, theres no need to ever wrap errors.

```rust
fn example(x: u32) -> DynResult<u32> {                  //returns a dynamic result
    match x {
        1      => Ok(x),                                //Ok()
        2..=4  => dynerr!(ExampleError1::ThisError(x)), //custom error
        5..=10 => dynerr!(ExampleError2::ThatError(x)), //different custom error
        _      => {
            std::env::current_dir()?;                   //an error not even defined by you!
            Ok(x)
        }
    }
}
```

\
`DynError` is an alias for `Box<dyn error::Error>`. Any error that implements `error::Error` can be turned into a `DynError`.\
`DynResult<T>` is just an alias for `Result<T, DynError>` so anything that works on a `Result<T>` will still work on a `DynResult<T>`.\
Dynerr works with any error type from any crate, as long as the type being returned implements `std::error::Error` then `DynResult<T>` should be able to handle it.\
To directly return a custom error its recommended to use the `dynerr!` macro instead of `Err()`.\
To match against the DynError contained in `DynResult<T>`, use the `dynmatch!` macro.\
`dynmatch!` usage looks similar to this:

```rust
 let i = match example(9) { //returns dyn error
     Ok(i) => i,
     Err(e) => {
         dynmatch!(e,                                                    //the error to match
             type ExampleError1 {                                        //enum error type
                 arm ExampleError1::ThisError(2) => panic!("it was 2!"), //arm [pattern] => {code}
                 _ => panic!("{}",e)                                     //_ => {code}
             },
             type ExampleError2 {                                        //another enum error type
                 arm ExampleError2::ThatError(8) => panic!("it was 8!"), //more arms to match against
                 arm ExampleError2::ThatError(9) => 9,
                 _ => panic!("{}",e)                                     //a final exhaustive match
             },
             _ => panic!("{}",e)                                         //final exhaustive match if type not found
         )
     }
 };
```

\
Aside from its main features, dynerr also has some simple macros to help with lazy logging.\
`log!` will log an event to the supplied file. Defaults to event.log if no log file supplied.\
`logged_panic!` will log an event to file then panic. Defaults to event.log if no log file supplied.\
`check!` will call `.unwrap_or_else(|e| logged_panic!(e))` on a result. Defaults to event.log if no log file supplied.\
If the supplied file doesn't exist then these macros will attempt to create the file.\
To delete a log file use the `clean!` macro.\
These macros all rely on either the `log` or `clean_log` functions. these functions are capable of panicking but shouldn't ever need to under normal circumstances.
\
\
A complete example:

```rust
use dynerr::*;
use std::{fmt, error};

//THIS SECTION IS CREATING THE FIRST CUSTOM ERROR
///a custom error type
#[derive(Debug)]

enum ExampleError1 {
    ThisError(u32),
}
//impl display formatting for error
impl fmt::Display for ExampleError1 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ExampleError1::ThisError(i)      => write!(f, "ExampleError1::ThisError: {}",i),
        }
    }
}
//impl error conversion for error
impl error::Error for ExampleError1 {}

//THIS SECTION IS CREATING THE SECOND CUSTOM ERROR
#[derive(Debug)]

enum ExampleError2 {
    ThatError(u32),
}
impl fmt::Display for ExampleError2 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ExampleError2::ThatError(i)      => write!(f, "ExampleError2::ThatError: {}",i),
        }
    }
}
impl error::Error for ExampleError2 {}


///THIS SECTION IS USING IT

///shows error handling capabilities using DynError
fn example(x: u32) -> DynResult<u32> {
    match x {
        1      => Ok(x),                                //Ok
        2..=4  => dynerr!(ExampleError1::ThisError(x)), //custom error
        5..=10 => dynerr!(ExampleError2::ThatError(x)), //different custom error
        _      => {
            std::fs::File::open("none")?;               //an error not even defined by you!
            Ok(x)
        }
    }
}

fn main() -> DynResult<()> {
    log!("this is a test", "test.log");
    let _i = match example(2) {
        Ok(i) => i,
        Err(e) => {
            dynmatch!(e,                                                                        //the DynError to be matched
                type ExampleError1 {                                                            //an error type
                    arm ExampleError1::ThisError(2) => logged_panic!("it was 2!"),              //arm [pattern] => {code}
                    _ => panic!("{}",e)                                                         //_ => {code}
                },
                type ExampleError2 {
                    arm ExampleError2::ThatError(8) => logged_panic!("it was 8!", "test.log"),
                    arm ExampleError2::ThatError(9) => 9,
                    _ => panic!("{}",e)
                },
                type std::io::Error {                                                           //an error type not defined by you
                    arm i if i.kind() == std::io::ErrorKind::NotFound => panic!("not found"),   //a match guard included in the match
                    _ => panic!("{}", e)
                },
                _ => panic!("{}",e)                                                             //what to do if error type isn't found
            )
        }
    };
    log!("do logged_panic! if error");
    let _i = check!(example(11));
    let _i = check!(example(9), "test.log");
    Ok(())
}
```