How to fix lifetime issue?

How to fix lifetime issue?
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4feff1b4a4c306f9514a98530d8f0daf

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

#[async_trait]
pub trait Handle {
    type Context;
    type Output;
    async fn call(&self, cx: Pin<&mut Self::Context>) -> Self::Output;
}

#[async_trait]
impl<F, Fut> Handle for F
where
    F: Send + Sync + 'static + Fn(Pin<&mut Context>) -> Fut,
    Fut: Future<Output = Result> + Send + 'static,
    Fut::Output: 'static,
    Context: Send + 'static,
{
    type Context = Context;
    type Output = Result;
    async fn call(&self, cx: Pin<&mut Self::Context>) -> Self::Output {
        (*self)(cx).await
    }
}

pub type Result = std::io::Result<()>;

pub struct Context {}

#[cfg(test)]
mod tests {
    use super::*;
    use futures::executor::block_on;

    #[test]
    fn it_works() {
        block_on(async move {
            async fn a(cx: Pin<&mut Context>) -> Result {
                println!("exec fn a");
                Ok(())
            }

            let mut cx = Context {};
            let mut cx: Pin<&mut Context> = Pin::new(&mut cx);
            let f: Box<dyn Handle<Context = Context, Output = Result>> = Box::new(a);
            // let _ = f(cx).await;
            // f.call(cx).await;
            // a.call(cx).await;
        });
    }
}

Compiling playground v0.0.1 (/playground)
error[E0271]: type mismatch resolving `for<'r> <for<'_> fn(std::pin::Pin<&mut Context>) -> impl core::future::future::Future {tests::it_works::{{closure}}#0::a} as std::ops::FnOnce<(std::pin::Pin<&'r mut Context>,)>>::Output == _`
  --> src/lib.rs:46:74
   |
46 |             let f: Box<dyn Handle<Context = Context, Output = Result>> = Box::new(a);
   |                                                                          ^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
   |
   = note: required because of the requirements on the impl of `Handle` for `for<'_> fn(std::pin::Pin<&mut Context>) -> impl core::future::future::Future {tests::it_works::{{closure}}#0::a}`
   = note: required for the cast to the object type `dyn Handle<Context = Context, Output = std::result::Result<(), std::io::Error>>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0271`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

This is because the future returned by your async fn a borrows from your context, but due to this 'static bound:

where
    F: Send + Sync + 'static + Fn(Pin<&mut Context>) -> Fut,
    Fut: Future<Output = Result> + Send + 'static,
//                                        ^ this bound

The returned future may not borrow anything. Unfortunately it is not possible write down a bound that allows the returned future to borrow from the provided parameter.

1 Like

I updated the codes, https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5d90fc7a071c5f42e3d86cf8a00630e2

Is there any way to get rid of the 'a?

No.

I created a crate for this. https://crates.io/crates/handle