# Feature suggestion: \_async counterparts for std methods that accept closures

**URL:** <https://internals.rust-lang.org/t/feature-suggestion-async-counterparts-for-std-methods-that-accept-closures/13763>\
**Category:** libs\
**Created:** [January 6, 2021, 6:04pm UTC](https://internals.rust-lang.org/t/feature-suggestion-async-counterparts-for-std-methods-that-accept-closures/13763 "2021-01-06T18:04:37Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![K4rakara](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/k4rakara/32/7592_2.png) [@K4rakara](https://internals.rust-lang.org/u/K4rakara)\
**Post date:** [January 6, 2021, 6:04pm UTC](https://internals.rust-lang.org/t/feature-suggestion-async-counterparts-for-std-methods-that-accept-closures/13763/1 "2021-01-06T18:04:38Z")

</div>

It'd be pretty nice for some of the stdlib methods that accept closures to have `xyz_async` counterparts, that accept asynchronous closures, allowing you to continue using `.await` just as you would in the parent scope (assuming the parent scope is an asynchronous function or closure).

Perhaps these would be best on separate traits, such as `IteratorAsync<T>` or `AsyncIterator<T>` as a counterpart for `Iterator<T>`.

Consider the following example:

```rust
macro_rules! rint_api {
  ($t:ident) => {
    &format!(r#"https://www.random.org/integers/?format=plain&col=1&base=10&min={min},&max={max}&num=1"#,
       min = std::$i::MIN,
       max = std::$t::MAX);
  },
  ($min:literal > $t:ident max > $max:literal) => {
     &format!(r#"https://www.random.org/integers/?format=plain&col=1&base=10&min={min},&max={max}&num=1"#,
       min = $min,
       max = $max);
  },
}

thread_local! {
  static FOO: RefCell<i32> = RefCell::new(0);
}

#[tokio::main]
async fn main() {
  // Since this is an asynchronous function, you can use .await here...
  
  FOO.with(|foo| {
    // ... but not here, since this is a synchronous closure.
    *foo += 42;
  });
  
  FOO.with_async(async move |foo| {
    // Here, you _could_ use .await, since it is now an asynchronous closure.
    // However, this method doesn't exist, hence why I'm making this post.
    let to_add = match reqwest::get(rint_api!(-512 > i32 > 512)).await {
      Ok(response) => match response.text().await() {
        Ok(text) => match text.parse::<i32>() {
          Ok(to_add) => to_add,
          Err(error) => panic!(format!("{}", error)),
        },
        Err(error) => panic!(format!("{}", error)),
      },
      Err(error) => panic!(format!("{}", error)),
    };
    *foo += to_add;
  }).await;

  FOO.with_async(async move |foo| {
    0..10.for_each_async(async move || {
      let to_add = match reqwest::get(rint_api!(-512 > i32 > 512)).await {
        Ok(response) => match response.text().await() {
          Ok(text) => match text.parse::<i32>() {
            Ok(to_add) => to_add,
            Err(error) => panic!(error),
          },
          Err(error) => panic!(error),
        },
        Err(error) => panic!(error),
      };
      *foo += to_add;
    }).await;
  }).await;
}

```

Its worth noting that a workaround is possible, but it's much less ergonomic: ( [Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=b2fe0f0802e7f7b79e884a8703b484e2) ( **Note:** _Broken, doesn't compile because of a CC error. Works if compiled locally._ ) )

Now I know that asynchronous closures are still unstable, but this would be an amazing feature to have. Let me know what you all think!

---

<div class="post-metadata">

**Author:** ![jhpratt](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jhpratt/32/11640_2.png) [@jhpratt](https://internals.rust-lang.org/u/jhpratt)\
**Post date:** [January 6, 2021, 7:18pm UTC](https://internals.rust-lang.org/t/feature-suggestion-async-counterparts-for-std-methods-that-accept-closures/13763/2 "2021-01-06T19:18:41Z")

</div>

Imo this is the kind of thing that could be done in a library like itertools. This would allow details to be hammered out before it (possibly) gets merged into stdlib.

---

<div class="post-metadata">

**Author:** ![K4rakara](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/k4rakara/32/7592_2.png) [@K4rakara](https://internals.rust-lang.org/u/K4rakara)\
**Post date:** [January 6, 2021, 7:29pm UTC](https://internals.rust-lang.org/t/feature-suggestion-async-counterparts-for-std-methods-that-accept-closures/13763/3 "2021-01-06T19:29:21Z")

</div>

That could work, although I think it would probably fit best in its own lib, as `itertools` and whatnot seem more targeted towards one specific part of `std`.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [January 6, 2021, 7:54pm UTC](https://internals.rust-lang.org/t/feature-suggestion-async-counterparts-for-std-methods-that-accept-closures/13763/4 "2021-01-06T19:54:20Z")

</div>

Async iterator sounds like `Stream`, depending on what you imagined there. (Look at `StreamExt` for its API.) It supports being [_created from an iterator_](https://docs.rs/futures/0.3/futures/stream/fn.iter.html "futures::stream::iter") and has API that can accept asynchronous closures (i.e. closures returning Futures), for example the asynchronous `map` equivalent `StreamExt::then`. Or an asynchronous `StreamExt::for_each`, basically taking async closures.

Regarding thread locals, a version of `with` that can accept an async closure seems a bit difficult, since to uphold the same guarantees that the created reference cannot leave the call to `with` and then leave then outlive the current thread you would, AFAICT, need to restrict the lifetime of the returned future in a way that makes it uncallable with proper async closures (since they want to store their arguments in the returned future.

I think the best solution to your code example would be to limit the scopes of calls to `with` to be way smaller, e.g. just doing `FOO::with(|foo| *foo += to_add);` calls.

* * *

So, [here’s a playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=f3a3727a3e82a641ba0ded59b84b3a00) with all these suggestions applied.

---

<div class="post-metadata">

**Author:** ![K4rakara](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/k4rakara/32/7592_2.png) [@K4rakara](https://internals.rust-lang.org/u/K4rakara)\
**Post date:** [January 6, 2021, 8:26pm UTC](https://internals.rust-lang.org/t/feature-suggestion-async-counterparts-for-std-methods-that-accept-closures/13763/5 "2021-01-06T20:26:28Z")

</div>

Oh sweet, I had no idea the `Stream` api existed. I've been using rust for a bit less than a year, but I'm new to async.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [April 6, 2021, 8:26pm UTC](https://internals.rust-lang.org/t/feature-suggestion-async-counterparts-for-std-methods-that-accept-closures/13763/6 "2021-04-06T20:26:42Z")

</div>

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