Struggled when designing libraries for async/await.
We can do this in the sync world:
// `f` is a reference-taking closure
pub fn call<F>(f: F) -> i32
where
F: Fn(&i32) -> i32,
{
f(&42)
}
#[test]
fn test_call() {
fn double(x: &i32) -> i32 { *x * 2 }
assert_eq!(call(double), 84);
}
Naive async equivalent doesn't compile.
#![feature(async_await)]
use std::future::Future;
// `f` is a reference-taking closure
pub async fn call<F, Fut>(f: F) -> i32
where
F: Fn(&i32) -> Fut,
Fut: Future<Output = i32>,
{
f(&42).await
}
// #[runtime::test]
async fn test_call() {
async fn double(x: &i32) -> i32 { *x * 2 }
assert_eq!(call(double).await, 84);
}
This is legit because Fut
is dependent on the HRTB lifetime parameter for F
. This means we need either Fn
internals or lifetime-dependent type constructor parameters.
However, the code below doesn't compile either:
#![feature(async_await)]
#![feature(unboxed_closures)]
use std::future::Future;
pub async fn call<F>(f: F) -> i32
where
F: for<'a> Fn<(&'a i32,)>,
for<'a> <F as FnOnce<(&'a i32)>>::Output: Future<Output = i32>,
{
f(&42).await
}
// #[runtime::test]
async fn test_call() {
async fn double(x: &i32) -> i32 { *x * 2 }
assert_eq!(call(double).await, 84);
}
Am I missing something?