Lifetimes with async function parameters

Hi,
I experimented with higher order async functions in Rust and can't figure out how I can communicate to the compiler that foo outlives the future execution. Or does it at all?

Playground example that doesn't compile

If I declare foo outside of applier(), I can bind the lifetimes of the mutable borrow of foo and the future to each other and it compiles. See this example: Playground

My question is: How can I declare foo inside of applier without running in lifetime issues?

Thanks in advance!

use std::future::Future;

use tokio; // 0.3.1

struct Foo {}

async fn worker(foo: &mut Foo) {}

trait AsyncSingleArgFnOnce<Arg>: FnOnce(Arg) -> <Self as AsyncSingleArgFnOnce<Arg>>::Fut {
    type Fut: Future<Output=<Self as AsyncSingleArgFnOnce<Arg>>::Output>;
    type Output;
}

impl<Arg, F, Fut> AsyncSingleArgFnOnce<Arg> for F
where
    F: FnOnce(Arg) -> Fut,
    Fut: Future,
{
    type Fut = Fut;
    type Output = Fut::Output;
}

async fn applier<F>(f: F)
where
    for<'a> F: AsyncSingleArgFnOnce<&'a mut Foo, Output=()>,
{
    let mut foo = Foo {};
    f(&mut foo).await
}

#[tokio::main]
async fn main() {
    applier(worker).await;
}

this works. Iā€™m not sure if the extra trait can be avoided.

Edit: added FnOnce supertrait

Edit2: refactored into more general trait and removed methods

Edit3: further generalization

2 Likes