Right way to continue processsing a future?

I'm now very confused what I'm doing wrong with these futures as there seem to be various outdated resources online on this. For instance this simple syntax:

async fn call_json_api(&self, url: Url) -> impl Future<Output = Result<Response>> {
        debug!("Calling URL: {:?}", url);
        self.client.get(url).send().map_err(Into::into)
}

async fn fetch(&self, arg: Arg) -> impl Future<Output = Result<T::InnerCls>> {
        self.call_json_api(self.api.url(arg)?)
            .and_then(|r| self.api.process_response(arg, r))
}

Gives me the following error:

error[E0599]: no method named `and_then` found for type `impl std::future::Future` in the current scope
   --> src/base.rs:468:14
    |
468 |             .and_then(|r| self.api.process_ticker_response(pair, r))
    |              ^^^^^^^^ method not found in `impl std::future::Future`
    |
    = note: the method `and_then` exists but the following trait bounds were not satisfied:
            `&impl std::future::Future : futures_util::try_future::TryFutureExt`
            `&mut impl std::future::Future : futures_util::try_future::TryFutureExt`
            `impl std::future::Future : futures_util::try_future::TryFutureExt`

The more confusing bit is that there is std::future::Future, core::Future and there was a whole crate futures. I'm using the head of the reqwest crate for the api call. Should I be using somehow await or what, really am confused now why I can't use and_then given there are so many "tutorials" on this online who do.

Yes, sorry, the state of async/futures in Rust is a bit of a mess at the moment.

Rust is switching from an experimental prototype of futures (v0.1) to the final version adopted as part of the standard library (std::future). Popular crates are gradually switching from one to another, so you'll likely encounter a mix of the two versions, and documentation for old and new version.

core::Future and std::Future is the same thing, and it's the new version. It's used by the async fn syntax, and few crates (mostly alpha/beta versions) support it at the moment.

futures::Future is the old version that required .and_then. It has wider support in the ecosystem for now, but it's going away.

1 Like

The and_then method from the old future ecosystem can be replaced by the await keyword.

async fn fetch(&self, arg: Arg) -> impl Future<Output = Result<T::InnerCls>> {
    let r = self.call_json_api(self.api.url(arg)?).await?;
    self.api.process_response(arg, r).await
}

async fn foo() -> T and fn foo() -> impl Future<Output = T> are basically the same definitions, so your
async fn call_json_api(&self, url: Url) -> impl Future<Output = Result<Response>> means that it is returns some impl Future<Output = impl Future<Output = Result<Response>> type.

With the new async-await syntax it could be smth like this:

async fn call_json_api(&self, url: Url) -> Result<Response> {
        debug!("Calling URL: {:?}", url);
        self.client.get(url).send().await.map_err(Into::into)
}

async fn fetch(&self, arg: Arg) -> Result<T::InnerCls> {
    let response = self.call_json_api(self.api.url(arg)?).await?;
    self.api.process_response(arg, response).await  # I presume that method returns Future too?
}

Great thanks for clarifying this for me. I know it is a bit of a mess, but now that the new Future is supposedly becoming stable, I did want to migrate asap to it as well.
From this, it seems that rather than using combinators with and_then and so on one just have to use the await.
Thanks again!

As a final note, how do you join multiple futures into a vec in order to run everything in parallel? I don't seem to find a join_all macro or function.

You can use the join and try_join functions from futures-preview.

There's also a macro join! and try_join! which implicitly call await on the given futures. Note that the macros require you to enable a certain feature in the crate to use them. See the documentation of the macros for more details.

But those, at least to my understanding work for fixed number of futures, e.g. 1,2,3,4 and I think up to 5. I have a Vec of those.

In that case you can use FuturesUnordered.

Ah, why that does not have smth like await_all that returns when everything is done?

If anyone needs it there is the futures_util::join_all which I think does the trick.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.