I want to make a function that creates some internal state, lets a user to modify it, and then proceeds to do other stuff. This works fine in the normal case but I also want to give the user an opportunity to do async stuff in their computation. When the future constraint comes into play everything goes to hell:
#![feature(trait_alias)]
use core::future::ready;
use core::future::Future;
use core::sync::atomic::AtomicU8;
// A function that lets the user modify an inner value.
fn mod_ref(f: impl for<'a> FnOnce(&'a AtomicU8)) -> u8 {
let a = AtomicU8::new(3);
f(&a);
a.into_inner()
}
// Same function but async.
trait AsyncW<'a, F> = FnOnce(&'a AtomicU8) -> F where F: Future<Output = ()>;
async fn mod_w_async<F>(f: impl for<'a> AsyncW<'a, F>) -> u8 {
let a = AtomicU8::new(3);
f(&a).await;
a.into_inner()
}
fn main() {
// This works fine.
mod_ref(|_| ());
// error: implementation of `FnOnce` is not general enough
mod_w_async(|_| ready(()));
}
error: implementation of `FnOnce` is not general enough
--> src/main.rs:27:5
|
27 | mod_w_async(|_| ready(()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 AtomicU8) -> std::future::Ready<()>` must implement `FnOnce<(&'1 AtomicU8,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 AtomicU8,)>`, for some specific lifetime `'2`
Why is this happening and is there a way to get it to work?
Note that mod_ref
and mod_w_async
are cut down for brevity. The important part is that the argument function takes as an argument a reference to the function's stack (or rather future's state machine).