pub mod capture_lifetime {
/// Mock a async FnOnce closure that captures at least a reference.
pub trait AsyncFnOnce<'a, In, Out> {
async fn call_once(self, message: In) -> Out;
}
#[macro_export]
macro_rules! async_closure_once {
(
{ $( $field:ident : $t:ty = $init:expr ),+ $(,)? };
async | $( $args:ident : $a:ty ),+ $(,)? | -> $out:ty
$e:block
) => {{
struct __AsyncClosure<'a> {
$( $field: $t , )+
_ph: std::marker::PhantomData<&'a ()>,
}
impl<'a> $crate::capture_lifetime::AsyncFnOnce<'a, ( $($a,)+ ), $out> for __AsyncClosure<'a> {
async fn call_once(self, __args: ( $($a,)+ )) -> $out {
let Self { $( $field , )+ .. } = self;
#[allow(unused_parens)]
let ( $( $args ),+ , ) = __args;
$e
}
}
#[allow(clippy::redundant_field_names)]
__AsyncClosure { $($field: $init , )+ _ph: std::marker::PhantomData }
}};
}
}
Usage: Rust Playground
async fn take_a_closure<'a, T, F>(cb: F) -> T
where
F: for<'s> AsyncFnOnce<'a, (&'s str,), T>,
{
let s = String::from("-");
let args = (&s[..],);
cb.call_once(args).await
}
async fn test() {
let outer = String::from("+");
let mut buf = String::new();
let cb3 = async_closure_once!({
s: &'a str = &outer,
buf: &'a mut String = &mut buf,
u: usize = 123
}; async |arg: &str| -> std::fmt::Result {
use std::fmt::Write;
write!(buf, "{s}{u}{arg}")
});
take_a_closure(cb3).await.unwrap();
assert_eq!(buf, "+123-");
}