If so, what does the function declaration / signature look like ?
An async function is just a function returning a Future
async fn foo<F, R>(cb: F) -> R::Output
where
F: Fn() -> R,
R: std::future::Future,
{
cb().await
}
Edit a few hours later : would it be possible to define Fn{Mut|Once}Async<Args, Output=Ret>
traits like the Fn{Mut/Once}
traits as shorthand FnAsync(Args) -> Ret
? (I imagine it would need the async traits feature and the associated type machinerie)
It’s absolutely possible to define short-hands for those kinds of trait bounds. It’s just not possible to be generic over the number of function arguments (on stable rust), so you’ll have to incorporate that number into the trait names as well, and live with some upper limit.
E.g.
use paste::paste;
use std::future::Future;
macro_rules! define_async_fn_traits {
($($J:literal)+) => {
define_async_fn_traits!{
[Once][] $($J)+
}
define_async_fn_traits!{
[Mut][] $($J)+
}
define_async_fn_traits!{
[][] $($J)+
}
};
([$($FNTYPE:ident)?][$($I:literal)*] $N:literal $($J:literal)*) => {
paste!{
trait [<Fn $($FNTYPE)? Async $N>]<$([<Arg $I>]),*>
: [<Fn $($FNTYPE)?>]($([<Arg $I>]),*) -> <Self as [<Fn $($FNTYPE)? Async $N>]<$([<Arg $I>]),*>>::OutputFuture
{
type OutputFuture: Future<Output = <Self as [<Fn $($FNTYPE)? Async $N>]<$([<Arg $I>]),*>>::Output>;
type Output;
}
impl<F: ?Sized, Fut, $([<Arg $I>]),*> [<Fn $($FNTYPE)? Async $N>]<$([<Arg $I>]),*> for F
where
F: [<Fn $($FNTYPE)?>]($([<Arg $I>]),*) -> Fut,
Fut: Future,
{
type OutputFuture = Fut;
type Output = Fut::Output;
}
}
define_async_fn_traits!{
[$($FNTYPE)?][$($I)* $N] $($J)*
}
};
([$($FNTYPE:ident)?][$($I:literal)*]) => {};
}
define_async_fn_traits!(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32);
////////////////////////////////////////////////////////////////////////////////
// demonstration:
async fn foo<F>(f: F) -> u32
where
F: FnOnceAsync3<String, bool, f32, Output = u32>,
{
f("hello".into(), true, 42.).await
}
async fn bar(_: String, _: bool, _: f32) -> u32 {
42
}
async fn usage() {
foo(bar).await;
}
Is there a shorter way to write this, something like:
async fn foo(cb: &'static async fn ...)
? Or we are stuck with the two generics.
With the macros written by @steffahn it would be :
async fn foo<F>(f: F) -> <F as FnOnceAsync0>::Output
where
F: FnOnceAsync0,
{
f().await
}
You know what... I’ve put these traits in a crate now (with slightly different name using
AsyncFn…
instead of FnAsync…
).
Or something like
async fn foo<O>(f: impl FnOnceAsync0<Output = O>) -> O {
f().await
}
would also work
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.