Documentation
use {
    problemo::{common::*, *},
    std::process::*,
};

// We can attach a std::process::ExitCode to control the exit code of our program.

// Note that it could very well be an ExitCode::SUCCESS.

// Also note that we do need to explicitly handle it, for example in our main() function.

// The common module has some conveniences for this common use case.

fn read_file(path: &str) -> Result<String, Problem> {
    // We can return an ExitError
    if path.is_empty() {
        return Err(ExitError::code_message(100, "sorry"));
    }

    // Or we can attach an ExitCode to any Problem
    std::fs::read_to_string(path)
        .into_problem()
        .with_exit_code(200)
}

// We'll fake main() here to make sure this example does not actually fail;
// If this were our real main(), the Err(ExitCode) would be used for the program's exit code

fn fake_main() -> Result<(), ExitCode> {
    // The use of ? is subtle here:
    // The common module implements Into<ExitCode> for Problem,
    // which automagically detects and uses an ExitCode if it is attached.

    read_file("non-existing.txt")?;

    Ok(())
}

fn main() {
    if let Err(exit_code) = fake_main() {
        println!("exit code: {:?}", exit_code);
    }
}