termination 0.1.2

Library that exposes Termination trait, similar to std::process::Termination.
Documentation
//! Library that exposes [`Termination`][1] trait, similar to [`std::process::Termination`][2].
//!
//! [`Examples`][3].
//!
//! [1]: trait.Termination.html
//! [2]: https://doc.rust-lang.org/std/process/trait.Termination.html
//! [3]: attr.display.html#examples

/// Procedural macro that allows `main` return values to use [`Display`][1] instead of
/// [`Debug`][2].
///
/// Any form of `fn main() -> _` should produce practically identical results with,
/// or without this annotation, the only difference being the trait used to format the error
/// values for printing.
///
/// Additionally, [`Termination`][3], (not to be confused with [`std::process::Termination`][4]) is
/// used by the annotated `main` instead.
///
/// # Examples
///
/// Functions that return unit type work the same.
///
/// ```
/// #[termination::display]
/// fn main() -> () {
///     ()
/// }
/// ```
///
/// It is possible to directly return exit code.
///
/// ```
/// #[termination::display]
/// fn main() -> i32 {
///     0
/// }
/// ```
///
/// Default implementation of `Termination` for `Result<(), E> where E: Display` prints error to
/// `stderr`, and returns appropriate error code to the operating system.
///
/// ```no_run
/// #[termination::display]
/// fn main() -> Result<(), &'static str> {
///     Err("Error: failed successfully.")
/// }
/// ```
///
/// It is still possible to use `!` as a return type; modified `main` never returns, therefore
/// macro-generated code will most likely be stripped out by compiler.
///
/// ```
/// #[termination::display]
/// fn main() -> ! {
///     std::process::exit(0);
/// }
/// ```
///
/// Custom implementations also are possible.
///
/// ```no_run
/// use termination::{display, Termination};
///
/// struct HelloWorld;
///
/// impl Termination for HelloWorld {
///     fn report(self) -> i32 {
///         println!("Hello world!");
///         42
///     }
/// }
///
/// #[display]
/// fn main() -> HelloWorld {
///     HelloWorld
/// }
/// ```
///
/// [1]: https://doc.rust-lang.org/std/fmt/trait.Display.html
/// [2]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
/// [3]: trait.Termination.html
/// [4]: https://doc.rust-lang.org/std/process/trait.Termination.html
pub use termination_attrib::display;

use std::fmt::Display;

/// Code signaling successful termination of the process.
///
/// Note that a `()`-returning `main` implicitly results in a successful
/// termination, so there's no need to return this from `main` unless
/// you're also returning other possible codes.
pub const EXIT_SUCCESS: i32 = 0;
/// Code signaling unsuccessful termination of the process.
///
/// If you're only returning this and [`SUCCESS`][1] from `main`, consider
/// instead returning [`Err(E)`][2] and [`Ok(())`][3] respectively, which will
/// return the same codes (but will also [`eprintln!`][4] the error).
///
/// [1]: constant.EXIT_SUCCESS.html
/// [2]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
/// [3]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
/// [4]: https://doc.rust-lang.org/std/macro.eprintln.html
pub const EXIT_FAILURE: i32 = 1;

/// A trait for implementing arbitrary return types in the `main` function.
///
/// The C-main function only supports to return integers as return type.
/// So, every type implementing the `Termination` trait has to be converted
/// to an integer.
///
/// The default implementations are returning [`SUCCESS`][1] to indicate
/// a successful execution. In case of a failure, [`FAILURE`][2] is returned.
///
/// [1]: constant.EXIT_SUCCESS.html
/// [2]: constant.EXIT_FAILURE.html
pub trait Termination {
    /// Is called to get the representation of the value as status code.
    /// This status code is returned to the operating system.
    fn report(self) -> i32;
}

impl Termination for () {
    /// Always returns [`SUCCESS`][1].
    ///
    /// [1]: constant.EXIT_SUCCESS.html
    fn report(self) -> i32 {
        EXIT_SUCCESS.report()
    }
}

impl Termination for i32 {
    /// Returns exact value that [`i32`][1] holds.
    ///
    /// [1]: https://doc.rust-lang.org/std/primitive.i32.html
    fn report(self) -> i32 {
        self
    }
}

impl<E: Display> Termination for Result<(), E> {
    /// Returns [`SUCCESS`][1] for [`Ok(())`][2], [`FAILURE`][3] for [`Err(E)`][4].
    ///
    /// [1]: constant.EXIT_SUCCESS.html
    /// [2]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Ok
    /// [3]: constant.EXIT_FAILURE.html
    /// [4]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
    fn report(self) -> i32 {
        match self {
            Ok(()) => ().report(),
            Err(e) => {
                eprintln!("{}", e);
                EXIT_FAILURE.report()
            },
        }
    }
}