Conversión de Tipos de Errores

use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::fs::{self, File};
use std::io::{self, Read};

#[derive(Debug)]
enum ReadUsernameError {
    IoError(io::Error),
    EmptyUsername(String),
}

impl Error for ReadUsernameError {}

impl Display for ReadUsernameError {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match self {
            Self::IoError(e) => write!(f, "IO error: {e}"),
            Self::EmptyUsername(filename) => write!(f, "Found no username in {filename}"),
        }
    }
}

impl From<io::Error> for ReadUsernameError {
    fn from(err: io::Error) -> ReadUsernameError {
        ReadUsernameError::IoError(err)
    }
}

fn read_username(path: &str) -> Result<String, ReadUsernameError> {
    let mut username = String::with_capacity(100);
    File::open(path)?.read_to_string(&mut username)?;
    if username.is_empty() {
        return Err(ReadUsernameError::EmptyUsername(String::from(path)));
    }
    Ok(username)
}

fn main() {
    //fs::write("config.dat", "").unwrap();
    let username = read_username("config.dat");
    println!("username or error: {username:?}");
}

Puntos clave:

  • La variable username puede ser Ok(string) o Err(error).
  • Utiliza la llamada a fs::write para probar las distintas situaciones: sin archivo, archivo vacío o archivo con nombre de usuario.

Se recomienda que todos los tipos de errores que no necesitan ser no_std implementen std::error::Error, que requiere Debug y Display. El crate Error para core solo está disponible en nightly, por lo que aún no es totalmente compatible con no_std.

Por lo general, es útil que también implementen Clone y Eq, siempre que sea posible, para facilitar las cosas a las pruebas y a los consumidores de tu biblioteca. En este caso, no podemos hacerlo de forma sencilla porque io::Error no los implementa.