error[E0308]: mismatched types
--> src/main.rs:6:8
|
1 | fn wrap<Fut, Ret>(f: impl FnOnce() -> Fut) -> impl FnOnce() -> Ret
| --- expected this type parameter
...
6 | || async {
| ________^
7 | | println!("Start");
8 | | f().await;
9 | | println!("Done");
10 | | }
| |_____^ expected type parameter `Ret`, found `async` block
|
= note: expected type parameter `Ret`
found `async` block `{async block@src/main.rs:6:8: 10:6}`
= help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `Ret`
error[E0562]: `impl Trait` is not allowed in the return type of `Fn` trait bounds
--> src/main.rs:1:64
|
1 | fn wrap<Fut, Ret>(f: impl FnOnce() -> Fut) -> impl FnOnce() -> impl std::future::Future
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
= note: see issue #99697 <https://github.com/rust-lang/rust/issues/99697> for more information
Is it fundamentally impossible to achieve the goal illustrated by the examples above?
Closures aren't able to have impl trait in return position (not yet...). Instead you can return a closure that returns a trait object. If you're working a lot with Futures stuff, you may want to consider Box::pinning the Future as well.
Your first formulation is incorrect as the caller of the function is allowed to choose Ret, not your function, so they might choose a different type that what your function returns.
The second formulation is logically correct, but unfortunately doesn't work due to a limitation of the language.
The trade-off is you have to repeat that trait for every argument arity (e.g. 0, 1, 2, ... arguments) and self type (e.g. &self for Fn, &mut self for FnMut, self for FnOnce) - a bit lame.