Allowing myself to use a couple of Nightly features, this is the closest I could get to it:
#![feature(async_fn_traits)]
#![feature(unboxed_closures)]
use core::marker::PhantomData;
use core::mem;
use core::pin::Pin;
struct Boxed<'a, F>(F, PhantomData<&'a ()>);
impl<'a, T, U, F> AsyncFnOnce<(T,)> for Boxed<'a, F>
where
F: AsyncFnOnce(T) -> U,
F::CallOnceFuture: 'a,
{
type CallOnceFuture = Pin<Box<dyn Future<Output = U> + 'a>>;
type Output = U;
extern "rust-call" fn async_call_once(
self,
args: (T,),
) -> Self::CallOnceFuture {
Box::pin(self.0(args.0))
}
}
struct TypeErased<'a, T, U>(
Box<
dyn AsyncFnOnce<
(T,),
CallOnceFuture = Pin<Box<dyn Future<Output = U> + 'a>>,
Output = U,
> + 'a,
>,
);
impl<'a, T, U> AsyncFnOnce<(T,)> for TypeErased<'a, T, U> {
type CallOnceFuture = Pin<Box<dyn Future<Output = U> + 'a>>;
type Output = U;
extern "rust-call" fn async_call_once(
self,
args: (T,),
) -> Self::CallOnceFuture {
self.0(args.0)
}
}
unsafe fn extend_lifetime<T, U>(
fun: impl AsyncFnOnce(T) -> U,
) -> impl AsyncFnOnce(T) -> U + 'static {
// SAFETY: up to caller.
unsafe {
mem::transmute::<TypeErased<'_, T, U>, TypeErased<'static, T, U>>(
TypeErased(Box::new(Boxed(fun, PhantomData))),
)
}
}
But that doesn't compile due to T
and U
not being 'static
, which doesn't make sense to me.
Why should a callback's input and output have to be 'static
for it to be 'static
?