Capturing async closure with &mut

I'm looking into create a simple web server api which would look something similar to this. I'm try to impl Handler for async function and async closures but running into what the type of F should be.

use async_trait::async_trait;
use std::sync::Arc;
use std::future::Future;
use std::pin::Pin;

enum Error {
    SomeError
}

struct Server {
    handler: Arc<dyn Handler>
}

impl Server {
    pub fn new<H: Handler>(handler: H) -> Self
    where
        H: Into<Arc<H>>,
    {
        Self {
            handler: handler.into(),
        }
    }
}


struct Context {}

impl Context {
    fn write(&mut self, _s: &str) {

    }
}

#[async_trait]
trait Handler : Send + Sync + 'static {
    async fn run(&self, ctx: &mut Context) -> Result<(), Error>;
}

#[async_trait]
 impl<Fun, Fut> Handler for Fun
 where
     Fun: Fn(&mut Context) -> Fut + Send + Sync + 'static,
     Fut: Future<Output = Result<(), Error>> + Send + 'static,
{
    async fn run(&self, ctx: &mut Context) -> Result<(), Error> {
        self(ctx).await?;
        Ok(())
    }
}

async fn helloworld(ctx: &mut Context) -> Result<(), Error> {
    ctx.write("hello world async fn!!!");
    Ok(())
}

fn main() {
    let _server = Server::new(|ctx: &mut Context| async move {
        ctx.write("hello world from closure!");
        Ok(())
    });

    let _server2 = Server::new(helloworld);
}
error: lifetime may not live long enough
  --> src/main.rs:57:51
   |
57 |       let _server = Server::new(|ctx: &mut Context| async move {
   |  _____________________________________-___________-_^
   | |                                     |           |
   | |                                     |           return type of closure `impl Future<Output = Result<(), Error>>` contains a lifetime `'2`
   | |                                     let's call the lifetime of this reference `'1`
58 | |         ctx.write("hello world from closure!");
59 | |         Ok(())
60 | |     });
   | |_____^ returning this value requires that `'1` must outlive `'2`

error[E0308]: mismatched types
  --> src/main.rs:62:20
   |
62 |     let _server2 = Server::new(helloworld);
   |                    ^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected trait `for<'r> <for<'r> fn(&'r mut Context) -> impl for<'r> Future<Output = Result<(), Error>> {helloworld} as FnOnce<(&'r mut Context,)>>`
              found trait `for<'r> <for<'r> fn(&'r mut Context) -> impl for<'r> Future<Output = Result<(), Error>> {helloworld} as FnOnce<(&'r mut Context,)>>`

For more information about this error, try `rustc --explain E0308`.
warning: `playground` (bin "playground") generated 1 warning
error: could not compile `playground` due to 2 previous errors; 1 warning emitted

This code

async move {
    ctx.write("hello world from closure!");
    Ok(())
}

Creates a future that captures ctx and returns that future. That means the borrow of Context passed to the handler needs to last as long as the future returned by the handler.

Passing Context by value would probably be easiest way to avoid the problem. Dealing with capturing lifetimes in futures can be a real pain.

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.