Search code examples
rustthiserror

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?


Solution

  • 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
        }
    }