caprica
caprica

Reputation: 4146

How to use thiserror to forward an error with a generic type parameter

Learning Rust, I am using the thiserror crate to wrap some exceptions.

This is the exception I want to wrap from the unrar crate:

#[derive(PartialEq)]
pub struct UnrarError<T> {
    pub code: Code,
    pub when: When,
    pub data: Option<T>,
}

My own code is this:

#[derive(Debug, Error)]
pub enum MyError {

    #[error(transparent)]
    Io(#[from] io::Error),

    #[error(transparent)]
    Unrar(#[from] unrar::error::UnrarError), // <-- missing generics

    #[error("directory already exists")]
    DirectoryExists,
}

The compiler complains about the missing generics type parameter on the UnrarError.

So I can add a type parameter:

#[derive(Debug, Error)]
pub enum MyError<T> {

    #[error(transparent)]
    Io(#[from] io::Error),

    #[error(transparent)]
    Unrar(#[from] unrar::error::UnrarError<T>),

    #[error("directory already exists")]
    DirectoryExists,
}

But if I do this, now all of my code that uses MyError needs to care about this type parameter, which in practical terms none of it cares about.

How should I idiomatically handle this situation?

Upvotes: 3

Views: 2995

Answers (1)

DenisKolodin
DenisKolodin

Reputation: 15071

I recommend you to use specific types or add your own variant. The UnrarError is designed to be generic where is shouldn't be generic.

Try the following:

#[derive(Debug, Error)]
pub enum MyError {

    #[error(transparent)]
    Io(#[from] io::Error),

    #[error(transparent)]
    Unrar(#[from] unrar::error::UnrarError<OpenArchive>),

    #[error(transparent)]
    UnrarProcessing(#[from] unrar::error::UnrarError<Vec<Entry>>),

    #[error("directory already exists")]
    DirectoryExists,
}

Or how I prefer to do in this case:

#[derive(Debug, Error)]
pub enum MyError {

    #[error(transparent)]
    Io(#[from] io::Error),

    #[error("unrar error")]
    Unrar,

    #[error("directory already exists")]
    DirectoryExists,
}

impl<T> From<unrar::error::UnrarError<T>> for MyError {
    fn from(err: unrar::error::UnrarError<T>) -> Self {
        // Get details from the error you want,
        // or even implement for both T variants.
        Self::Unrar
    }
}

Upvotes: 7

Related Questions