Code
fn get<T, F>(&mut self, path: &str, callback: F)
where
F: Fn(&mut Context) -> T + 'static + Send + Sync,
T: Future<Output = ()> + 'static + Send + Sync,
{
self.gets.push((
path.to_string(),
Arc::new(Box::new(move |c| Box::pin(callback(c)))),
));
}
async fn index(ctx: &mut Context) {
ctx.body = "Hello World".to_string();
println!("Hello");
}
get("/", index);
Error
mismatched types
expected associated type `<for<'_> fn(&mut structs::Context) -> impl futures::Future<Output = ()> {index} as FnOnce<(&mut structs::Context,)>>::Output`
found associated type `<for<'_> fn(&mut structs::Context) -> impl futures::Future<Output = ()> {index} as FnOnce<(&mut structs::Context,)>>::Output`
the required lifetime does not necessarily outlive the static lifetimerustcE0308
get.rs(101, 32): the lifetime requirement is introduced here
The issue is I am using mutable reference Fn(&mut Context) & rust unable to get the lifetime.
Thank you
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);
}
2 Likes