Async closures and workarounds

I know actual async closures are an unstable feature, but I was wondering what a good way to work around this would be. I have an async function which takes two closures, the first one is to create a basic filter for incoming frames, and the second closure is to process the contents of the frames. Simplified:

pub async fn recvloop<C, S, P>(
  conn: &mut Framed<C, Codec>,
  kill: Option<killswitch::Shutdown>,
  mut storeq: S,
  procmsg: P
) -> Result<(), Error>
where
  C: AsyncRead + AsyncWrite + Unpin,
  S: FnMut(&MsgInfo) -> Result<(StoreType, StoreType), Error>,
  P: Fn(Msg) -> Result<(), Error>
{
   // ...
}

The StoreTypes returned from store are used to instruct recvloop() what to do with the incoming data. If the application decides to process it, then procmsg will be called to allow it to perform the processing. This has worked fine, until procmsg needed to run async code.

I read a blog post where someone argued "just stick it (the closure body) in an async { } block". I'm not sure how this is supposed to work -- is the idea that the async block returns a future that, in my case, recvloop() would .await on? How would one express that (specifically, the trait bound for P).

Any other (recommended) ways to do this? I also considered using channels to send msg's to a separate async task.

Accept a generic function that returns a type that implements Future, then .await the result. A simple example:

async fn with_async_callback<Fut: Future<Output = i32>, F: FnOnce() -> Fut>(f: F) -> i32 {
    f().await
}

with_async_closure(|| async { 123 })
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.