I don't think you can accomplish everything you want.
F: for<'a> Fn(&'a mut T) -> R + Send + Sync + Copy + 'static, // how to relate 'a to -
R
can only represent a single type outside of the for<'a>
binder. But you want it to represent a future which captures the binder lifetime ('a
). So a type parameter on boxed
like R
cannot fulfill the role. However, there's not yet a way to name the anonymous future type constructor returned from the closure, either.
The AsyncFn
traits were introduced as an attempt to alleviate this challenge, among others, but they fall short: the stable syntax does not give you a way to put bounds on the future type, only the return type. But here you're wanting to put a Send
bound on the return type.
Here's an example of a partial solution. The returned futures cannot be assumed to be Send
.
Side-bar:
It looks like you're using -> impl ... + 'a
where you mean -> impl ... + use<'a>
. On edition 2024+, you usually don't want + 'a
. That was usually used as a sort of hack in earlier editions to make the opaque return type capture 'a
by mentioning it. But it also puts an outlives bound on the opaque return type, which in the general case, is not needed. In edition 2024+, all lifetimes are captured by default (not just mentioned lifetimes), so the hack is no longer necessary.
Here it's unnecessary:
fn x<'a>(_: &'a i32) -> impl Future<Output = i32> + 'a
Relatedly, here, it does not mean that R
is parameterized by / captures 'a
.
where
F: for<'a> Fn(&'a mut T) -> R + Send + Sync + Copy + 'static, // how to relate 'a to -
T: Message + Default + 'static, // |
U: Message + 'static, // |
R: Future<Output = U> + Send + 'a, // <-----------------------------------------------
There's no way to make a type parameter like R
be dependent on a lifetime introduces in a deeper scope, like the for<'a>
introduces elsewhere in the where
clauses. Rust doesn't have generic type constructors; there is no direct mechanism for
// vvvv
fn boxed<F, R<*>, T, U>(...)
where
// vvvvv
F: for<'a> Fn(&'a mut T) -> R<'a> + Send + Sync + Copy + 'static,
(And because futures and closures are unnameable, the indirect techniques usually don't help for your use case without piling on more type erasure.)