How to match on multiple different error types resulting from joining futures?

Viewed 296

I am using the library thiserror and want to match on multiple different errors.

My main.rs:

let bus1_fut = bus1::start();
let bus2_fut = bus2::start();
match try_join!(
        bus1_fut,
        bus2_fut
    ) {
        Ok(_) => {}
        Err(e) => match e {
            Bus1Error::Error0 => info!("{}", e),
            Bus1Error::IOError(err) => error!("Failed to execute: {}", err),
            Bus2Error::Error1 => info!("{}", e),
            Bus2Error::IOError(err) => error!("Failed to execute: {}", err),
        }
    }

In a separate crate, business1.rs:

#[derive(Error, Debug)]
pub enum Bus1Error {
    #[error("Error.")]
    Error0,
    #[error(transparent)]
    IOError(#[from] std::io::Error),
}

Again, in a separate crate, business2.rs:

#[derive(Error, Debug)]
pub enum Bus2Error {
    #[error("Error.")]
    Error1,
    #[error(transparent)]
    IOError(#[from] std::io::Error),
}

The functions bus1::start() and bus2::start() return Result<(), Bus1Error> and Result<(), Bus2Error>, respectively.

Unfortunately, I get the compile errors:

31 |       match try_join!(
33 | |         bus1_fut,
34 | |         bus2_fut
35 | |     ) {
   | |_____^ expected enum `Bus1Error`, found enum `Bus2Error`


    Bus2Error::Error1 => info!("{}", e),
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Bus1Error`, found enum `Bus2Error`

try_join is from tokio.

I am not sure how I can match on these different error types.

EDIT: I tried to implement the suggestions provided by Shepmaster as follows.

In my main.rs I have now added:

#[derive(Error, Debug)]
pub enum MainError {
    #[error("Blah.")]
    Bus1Error(Bus1Error),
    #[error("Blah.")]
    Bus2Error(Bus2Error),
}

However, I still get the same errors. Do I have to adapt the return values of bus1::start() and bus2::start() to match now my MainError? For me, this would not make sense, because I do not want to have any code from main.rs in these two crates.

1 Answers

Thanks to Shepmaster I was able to resolve this in the following way:

In my main.rs:

use futures::TryFutureExt;


#[derive(Error, Debug)]
pub enum MainError {
    #[error("Blah.")]
    Bus1Err(#[from] Bus1Error),
    #[error("Blah.")]
    Bus2Err(#[from] Bus2Error),
}

...

let bus1_fut = bus1::start();
let bus2_fut = bus2::start();
match try_join!(
        bus1_fut.map_err(MainError::from),
        bus2_fut.map_err(MainError::from)
    ) {
        Ok(_) => {}
        Err(e) => match e {
            MainError::Bus1Err => info!("{}", e),
            MainError::Bus2Err => info!("{}", e),
        }
    }
Related