Async-await experience reports

Hi there, here is my 50 cents.

How long have you been using the syntax: more than 6 month

What code are you working on: Commercial project - scraping data from different sources(providers).

What environment: vscode (using rls and rust-analyzer both eating almost half of my 16G memory) intellij-idea(no debugging:( )

What happened: I have tried new .await syntax in several places. I don’t feel significant usability increase of that approach, because I don’t has a lot of futures which outputs futures to leverage full power of the postfix syntax (interesting what kind of project may have a lot of futures outputting futures?), in most of the times .map or .and_then is enough IMHO. Here some very typical part of the project:

       let urls_len = await!(self.listing_urls_repo.count(providers.clone(), skip))?;
       let stream = await!(self.listing_urls_repo.list(providers, skip))?;

       let stream = stream
           .map(move |res| {
               let mut sender = sender.clone();

               async move {
                   let res: Result<_, Error> = try {
                       let url = res?;
                       let kind = url.provider.clone().try_into().unwrap();
                       let id = url.provider_id;
                       
                       let new_listing = await!(self.providers.get_listing(kind, id.clone()))
                           .map_err(|err| ErrorKind::FetchFail(format!("provider: {}; id: {}; err: {}", kind, &id, err)))?;

                       let url_update = UpdateListingUrl {
                           id: url.id,
                           status: 1
                       };

                       await!(sender.send((new_listing, url_update))).unwrap();
                   };

                   res       
               }
           })
       .buffer_unordered(100);

       pin_mut!(stream);
       while let Some(_item) = await!(stream.next()) {
           // increment progress bar
       }

And what I would be happy rust have instead of .await:

  1. pattern matching ? - it is most desirable, here is example:
let task1 = async move { ... }
let task2 = async move { ... }

let (val1?, val2?) = await!(futures::join(task1, task2));
// now I has something like:
// let (res1, res2) = await!(futures::join(task1, task2));
// let (val1, val2) = (res1?, res2?);
// in most cases just
// let _ = (res1?, res2?);
  1. more ergonomics with try + async block. One more annoying thing is async move and error type elision:
let task = async move {
   try { // error type not elided :(
       let a = await!(x)?;
       //    ...
   }
}

and I have to write like:

let task = async move {
   let err: Result<_, Error> = try { // error type not elided :(
       let a = await!(x)?;
       //    ...
   };

   err
}

Other background information: initially was based on futures 0.1 with tokio’s compatibility to futures 0.3

now (few month ago) I have got rid of tokio, used futures 0.3’s block_on and withoutboats’s juliex for spawn and now I have futures 0.3 with compat 0.1 in some cases (like when dealing with tokio-postgres)

find -name *.rs | xargs wc -l - 11646

find -name *.rs | xargs rg await! | wc -l - 311

find -name *.rs | xargs rg "async fn" | wc -l - 132

2 Likes