3

I need to run 4 functions concurrently but one of them is different based on user input.

If I use "if-else" I get "if and else have incompatible types" due to Future.

The only way I see is to make a third function that selects from the other two, but it doesn't allow (to my knowledge) to run concurrently due to awaiting.

Another way is to make two different join! but that seems "code expensive".

What should I do in this situation?

tokio::join!(
    self.func1(),
    if self.flag() {
        self.func2()
    } else {
        self.func3()
    },
    self.func4(),
    self.func5()
);

The function signature is as follows:

pub async fn funcN(&self) -> Result<Vec<String>> {
kmdreko
  • 42,554
  • 6
  • 57
  • 106
PFA hard
  • 81
  • 5

3 Answers3

3

The probably easiest way is to use a Box and dynamic dispatch. For example, this compiles:

tokio::join!(
    func1(),
    if flag() {
        Box::pin(func2()) as Pin<Box<dyn Future<Output = _>>>
    } else {
        Box::pin(func3()) as Pin<Box<dyn Future<Output = _>>>
    },
    func4(),
    func5()
);

Playground

user4815162342
  • 141,790
  • 18
  • 296
  • 355
3

You can use if inside an async block to produce a single future type from two:

tokio::join!(
    func1(),
    async {
        if flag() {
            func2().await
        } else {
            func3().await
        }
    },
    func4(),
    func5()
);

This has slightly different scheduling than the other answers: the flag() call is made part of the future rather than run immediately. If this is undesirable, you could put the boolean result in a variable beforehand.

Other than that, this is much like the Either approach, but can generalize to more than two choices.

Kevin Reid
  • 37,492
  • 13
  • 80
  • 108
2

You can use the futures::future::Either enum:

tokio::join!(
    self.func1(),
    if self.flag() {
        Either::Left(self.func2())
    } else {
        Either::Right(self.func3())
    },
    self.func4(),
    self.func5()
);

Playground

Francis Gagné
  • 60,274
  • 7
  • 180
  • 155