How to hold an async function as variable

Hi I'm new to rust and want to write a simple server.

In server I need to hold a series of async function to process a Context, so I write like this:

struct Context<'a> {
    s: &'a str
}

And a simple wrapper for function:

struct Wrapper {
    f: Box<dyn Fn(&mut Context) -> Pin<Box<dyn Future<Output = bool>>>>
}

impl Wrapper {
    fn new<T>(g: fn(&mut Context) -> T) -> Wrapper where T: Future<Output = bool> {
        Wrapper {
            f: Box::new(move |a| Box::pin(g(a)))
        }
    }
}

Now it don't compile because compiler complains that T may not live long enough.
I try this in my understand but still can't compile:

fn new<'a, T>(g: fn(&mut Context<'a>) -> T) -> Wrapper where T: Future<Output = bool> + 'a

It says g has lifetime 'a but it needs to satisfy a 'static lifetime requirement.
so I satisfy it, though I think I can promise I will consume/await that Future instantly:

fn new<T>(g: fn(&mut Context) -> T) -> Wrapper where T: Future<Output = bool> + 'static

Now it compiles, I try to use it:

fn main() {
    Wrapper::new(|a| async {
        return true
    });
}

That pass.

Add some logic:

fn main() {
    Wrapper::new(|a| async {
        let s = a.s;
        return true
    });
}

It don't compile.
Error:

the type `impl std::future::Future` does not fulfill the required lifetime
note: type must satisfy the static lifetimerustc(E0477)
cannot infer an appropriate lifetime due to conflicting requirements
note: but, the lifetime must be valid for the static lifetime...rustc(E0495)

That's... confusing that I can't find another conflicting lifetime.

Where I got wrong?

Full code:

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

struct Context<'a> {
    s: &'a str
}

struct Wrapper {
    f: Box<dyn Fn(&mut Context) -> Pin<Box<dyn Future<Output = bool>>>>
}

impl Wrapper {
    fn new<T>(g: fn(&mut Context) -> T) -> Wrapper where T: Future<Output = bool> + 'static {
        Wrapper {
            f: Box::new(move |a| Box::pin(g(a)))
        }
    }
}

fn main() {
    Wrapper::new(|a| async {
        let s = a.s;
        return true
    });
}

If you insist on having the Context have a lifetime, then this is probably the best you can do:

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

struct Context<'a> {
    s: &'a str
}

struct Wrapper {
    f: Box<dyn for<'a> Fn(Context<'a>) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> + Send + Sync>
}

impl Wrapper {
    fn new<F>(g: F) -> Wrapper
    where
        F: for<'a> Fn(Context<'a>) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>>,
        F: Send + Sync + 'static,
    {
        Wrapper {
            f: Box::new(move |a| Box::pin(g(a)))
        }
    }
}

fn main() {
    Wrapper::new(|a| Box::pin(async move {
        let s = a.s;
        return true
    }));
}
1 Like

Thank you! It seems I need to learn more about rust grammar.

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.