Mapping returned `Result` of main to an exit code?

The signature of my main function is fn main()->Result<(), Box<dyn std::error::Error>>.

However for different returned Errors, the exit code are all 1. And for Ok(()), the exit code is surely 0.

I know that there IS a method that can do this mapping, based on std::process::exit.

But is there a better way to do this?

You're probably looking for the Termination trait.

It works something like this:

enum ProcessResult {
  Good,
  Bad,
  Yikes
}

impl Termination for ProcessResult {
  fn report(self) -> ExitCode {
    match self {
      ProcessResult::Good => {
        ExitCode::from(0)
      }
      ProcessResult::Bad => {
        println!("Not good");
        ExitCode::from(1)
      }
      ProcessResult::Yikes => {
        println!("Major bad")
        ExitCode::from(2)
      }
    }
  }
}

fn main() -> ProcessResult {
  ProcessResult::Good
}

A few things to note:

  • This gives you the ability to customize the failure case output, which is nice.
  • It's not possible, in stable, to get implicit conversions using ? from Result to ProcessResult (or whatever one calls it). In nightly it can be done though, and the magic sauce is try-trait-v2.

To avoid needing a bunch of .into() in main() I usually have a main() which calls main2(), and it's merely the role of main() to call main2() and convert its Result into the ProcessResult. When/if try-v2 is stabilized, this hack can be dropped (well, unless changes..).

6 Likes

Of course such a main could also just return the error code directly, without needing to bother with the ProcessResult type.

1 Like