diff options
Diffstat (limited to 'src/exit.rs')
| -rw-r--r-- | src/exit.rs | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/src/exit.rs b/src/exit.rs new file mode 100644 index 0000000..3c7b724 --- /dev/null +++ b/src/exit.rs @@ -0,0 +1,54 @@ +use std::{ + error::Error, + io, + process::{ExitCode, Termination}, +}; + +use crate::error::chain; + +/// Formats errors for display before exiting the program. +/// +/// When this is used as the return type of a program's `main`, it can be used to capture any errors +/// during the execution of the program and to display them in a readable format at exit time: +/// +/// ```no_run +/// # use std::{error::Error, io}; +/// fn main() -> pilcrow::cli::Exit<impl Error> { +/// my_complicated_task().into() +/// } +/// +/// fn my_complicated_task() -> Result<(), impl Error> { +/// Err(io::Error::other("stand-in for a real failure")) +/// } +/// ``` +/// +/// If constructed with an `Ok(())`, the resulting `Exit` indicates successful execution, and, when +/// returned from `main`, will cause the program to exit with a successful exit status. If constructed +/// with any `Err(…)` value, the resulting `Exit` indicates unsuccessful execution, and, when +/// returned from `main`, will cause the program to print the error (along with its `source()` +/// chain, if any) before exiting with an unsuccessful exit status. +pub struct Exit<E>(pub Result<(), E>); + +impl<E> From<Result<(), E>> for Exit<E> { + fn from(result: Result<(), E>) -> Self { + Self(result) + } +} + +impl<E> Termination for Exit<E> +where + E: Error, +{ + fn report(self) -> ExitCode { + let Self(result) = self; + match result { + Ok(()) => ExitCode::SUCCESS, + Err(err) => { + // if we can't write the error message to stderr, there's nothing else we can do + // instead, and we're about to exit with a failure anyway. + let _ = chain::format(&mut io::stderr().lock(), &err); + ExitCode::FAILURE + } + } + } +} |
