I'll assume you're currently using the solution from your last question. The problem is that every callback is required to return a Future + 'static
, but any async function that captures an &'a mut Context
can only return a Future + 'a
(since the future must store the reference). This is what results in the compiler error: it's saying that the opaque future type corresponding to index
is not 'static
.
Unfortunately, the fix for this is somewhat involved. We want to assert that the callback returns a Future + 'a
when given an &'a mut Context
, for any lifetime 'a
. This can be done with a higher-rank trait bound. But since the future type is distinct from the callback type, we must add a helper Callback<'a>
trait, which asserts that a function has type Fn(&'a mut Context) -> impl Future + 'a
. Altogether, it looks something like this (Rust Playground):
use futures::{future::BoxFuture, Future};
use std::{marker::Send, sync::Arc};
struct Context {
body: String,
}
trait Callback<'a> {
fn call(&self, ctx: &'a mut Context) -> BoxFuture<'a, ()>;
}
impl<'a, T, F> Callback<'a> for F
where
F: Fn(&'a mut Context) -> T,
T: Future<Output = ()> + Send + 'a,
{
fn call(&self, ctx: &'a mut Context) -> BoxFuture<'a, ()> {
Box::pin(self(ctx))
}
}
struct Store {
gets: Vec<(String, Arc<Box<dyn for<'a> Callback<'a>>>)>,
}
impl Store {
fn get<F>(&mut self, path: &str, callback: F)
where
F: for<'a> Callback<'a> + 'static,
{
self.gets
.push((path.to_string(), Arc::new(Box::new(callback))));
}
}
async fn index(ctx: &mut Context) {
ctx.body = "Hello World".to_string();
println!("Hello");
}
fn main() {
let mut s = Store { gets: Vec::new() };
s.get("/", index);
}