Skip to main content

AsyncNativeFn

Type Alias AsyncNativeFn 

Source
pub type AsyncNativeFn = fn(*mut Vm, u32, u32) -> Pin<Box<dyn Future<Output = Result<u32, LuaError>>>>;
Expand description

v1.1 B10 Stage 2 — async-native function ABI. Returns a Pin<Box<dyn Future>> that resolves to the return-value count (same convention as sync crate::runtime::value::NativeFn: write results into the caller’s slot via the borrowed Vm, then yield the count back).

§Safety contract

The first parameter is *mut Vm rather than &mut Vm because the returned Pin<Box<dyn Future>> is 'static (the trait object erases lifetimes) and we cannot tie it to the caller’s borrow without for<'vm> HRTBs that the trait system rejects on dyn futures. Implementors must reborrow inside the future:

fn my_async(
    vm: *mut Vm,
    func_slot: u32,
    nargs: u32,
) -> Pin<Box<dyn Future<Output = Result<u32, LuaError>>>> {
    Box::pin(async move {
        // SAFETY: the dispatcher is suspended and EvalFuture
        // holds the unique &mut Vm borrow for the future's
        // entire lifetime; no concurrent access can occur.
        let vm = unsafe { &mut *vm };
        // ... read args from vm.stack[func_slot+1..], do async
        //     work (e.g. `sleep(...).await`), write results back
        //     to vm.stack[func_slot..], return their count ...
        Ok(0)
    })
}

The Vm is exclusively owned by the active EvalFuture for the suspension’s full lifetime (the dispatcher is paused; the host’s executor is the only driver). This makes the unsafe { &mut *vm } reborrow sound provided the future doesn’t leak the borrow past its own await boundaries.

The native is invoked exactly once per Lua call site. The future is polled by EvalFuture::poll; on Poll::Ready(Ok(n)) the dispatcher resumes, treats slots [func_slot, func_slot+n) as the return list, and continues. On Poll::Ready(Err(e)) the error propagates as if a sync native had returned it.