1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! 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()
            },
        }
    }
}