exit_safely 0.1.0

Enables exiting safely with custom exit codes while still calling `Drop` as needed. Aims for minimal magic and maximum flexibilty.
Documentation
# Exit rust apps safely

[`std::process::exit`](https://doc.rust-lang.org/std/process/fn.exit.html) warns:
> "Note that because this function never returns, and that it terminates the process, no destructors on the current stack or any other thread’s stack will be run. If a clean shutdown is needed it is recommended to ... simply return a type implementing Termination ... from the main function and avoid this function altogether"

`exit_safely` provides a simple and highly transparent option to `derive(Termination)` from your own enum with a very simple API which still provides you full control over exit codes and what to (safely) output to stderr.

Minimal magic, maximum flexibilty, zero boilerplate.

## Example

Here's the full example from the integration tests, showing how this plays really nicely with `Try` (derived via [try_v2](https://docs.rs/try_v2/latest/try_v2/))

```rust
#![feature(never_type)]
#![feature(try_trait_v2)]
use exit_safely::Termination;
use try_v2::*;

use std::io;

use std::process::Termination as _T; // Needed as trait bound for Exit

#[derive(Debug, Termination, Try, Try_ConvertResult)]
#[repr(u8)]
enum Exit<T: _T> {
    Ok(T) = 0,

    // Any io errors are ExitCode 1, delegate stderr contents to io::Error's Display
    FileError(io::Error) = 1,

    // ExitCode 2 can be manually created with a String to be sent to stderr
    InvocationError(String) = 2,

    // Just exit with ExitCode 3 and nothing extra sent to stderr
    Other = 3,
}

// Allows for simple `?` propogation of `io::Error`s
impl<T: _T> From<io::Error> for Exit<T> {
    fn from(err: io::Error) -> Self {
        Exit::FileError(err)
    }
}

// And for validation of data you can impl From<foo> for Exit
struct File {
    pass_or_fail: String,
    contents: String,
}

impl From<File> for Exit<()> {
    fn from(file: File) -> Self {
        match file.pass_or_fail.as_str() {
            "PASS" => Exit::Ok(()),
            _ => Exit::Other,
        }
    }
}

// if given too few args it will fail with ExitCode 2 (InvocationError) and a message
// if given `<FILENAME> <FAIL>` it will fail with ExitCode (Other) 3,
// if given `<FILENAME> <ANYTHING_ELSE>` it will check file exists
fn main() -> Exit<()> {
    println!("Hello, world!");

    let mut args = std::env::args();

    let filename = args
        .nth(1)
        // `ok_or(Exit::foo)?` will exit safely with ExitCode from `foo`
        .ok_or(Exit::InvocationError("REALLY Not enough args".to_string()))?;

    let pass_or_fail = args
        .next()
        .ok_or(Exit::InvocationError("Not enough args".to_string()))?;

    // Using `?` on an Error which can convert to Exit will also exit safely with the relevant ExitCode
    let contents = std::fs::read_to_string(&filename)?;
    let file = File {
        pass_or_fail,
        contents,
    };

    // If everything goes well, check the data ...
    Exit::from(file)

    // Or you could of course just `Exit::Ok(())`
}
```