Error Propagation With the Result Type

Return Result from functions and use the question-mark operator to propagate errors, keeping failure paths explicit and composable.

RustResilience

Code

snippet
use std::fs;
use std::io;
use std::num::ParseIntError;

#[derive(Debug)]
enum ConfigError {
    Io(io::Error),
    InvalidPort(ParseIntError),
}

impl From<io::Error> for ConfigError {
    fn from(error: io::Error) -> Self {
        ConfigError::Io(error)
    }
}

impl From<ParseIntError> for ConfigError {
    fn from(error: ParseIntError) -> Self {
        ConfigError::InvalidPort(error)
    }
}

fn read_port(path: &str) -> Result<u16, ConfigError> {
    let raw = fs::read_to_string(path)?;
    let port: u16 = raw.trim().parse()?;
    Ok(port)
}

fn main() {
    match read_port("port.txt") {
        Ok(port) => println!("port = {port}"),
        Err(error) => eprintln!("config error: {error:?}"),
    }
}