Refactor luaffi proc-macro

This commit is contained in:
2025-06-24 19:30:39 +10:00
parent f8e7b8ae62
commit 3dd375b071
6 changed files with 740 additions and 522 deletions

View File

@@ -1,6 +1,6 @@
use crate::{
__internal::{display, type_id},
Cdef, CdefBuilder, FfiReturnConvention, IntoFfi, Metatype, MetatypeBuilder, Type, TypeBuilder,
Cdef, CdefBuilder, IntoFfi, Metatype, MetatypeBuilder, Type, TypeBuilder, TypeType,
UnsafeExternCFn,
};
use luaify::luaify;
@@ -43,7 +43,7 @@ pub struct lua_future<F: Future<Output: IntoFfi>> {
sig: Signature,
poll: fn(Pin<&mut Self>, cx: &mut Context) -> Poll<()>,
state: State<F>,
take: unsafe extern "C" fn(&mut Self) -> <F::Output as IntoFfi>::To,
take: unsafe extern "C" fn(&mut Self) -> <F::Output as IntoFfi>::Into,
drop: unsafe extern "C" fn(&mut Self),
}
@@ -94,7 +94,7 @@ impl<F: Future<Output: IntoFfi>> lua_future<F> {
}
}
unsafe extern "C" fn take(&mut self) -> <F::Output as IntoFfi>::To {
unsafe extern "C" fn take(&mut self) -> <F::Output as IntoFfi>::Into {
// `fut:__take()` returns the fulfilled value by-value (not by out-param) because if we
// preallocate a cdata for the out-param and the thread for some reason gets dropped and
// never resumed, the GC could call the destructor on an uninitialised cdata.
@@ -136,8 +136,12 @@ unsafe impl<F: Future<Output: IntoFfi> + 'static> Type for lua_future<F> {
display!("future__{:x}", type_id::<F>())
}
fn ty() -> TypeType {
TypeType::Aggregate
}
fn cdecl(name: impl Display) -> impl Display {
display!("struct future__{:x} {name}", type_id::<F>())
display!("struct {} {name}", Self::name())
}
fn build(s: &mut TypeBuilder) {
@@ -148,7 +152,7 @@ unsafe impl<F: Future<Output: IntoFfi> + 'static> Type for lua_future<F> {
unsafe impl<F: Future<Output: IntoFfi> + 'static> Cdef for lua_future<F> {
fn build(s: &mut CdefBuilder) {
s.field_opaque(mem::offset_of!(Self, take)) // opaque .sig, .poll and .state
.field::<UnsafeExternCFn<(&mut Self,), <F::Output as IntoFfi>::To>>("__take")
.field::<UnsafeExternCFn<(&mut Self,), <F::Output as IntoFfi>::Into>>("__take")
.field::<UnsafeExternCFn<(&mut Self,), ()>>("__drop");
}
}
@@ -162,24 +166,25 @@ unsafe impl<F: Future<Output: IntoFfi> + 'static> Metatype for lua_future<F> {
}
unsafe impl<F: Future<Output: IntoFfi> + 'static> IntoFfi for lua_future<F> {
type To = lua_future<F>;
type Into = lua_future<F>;
fn convert(self) -> Self::To {
fn convert(self) -> Self::Into {
self
}
fn postlude(ret: &str, _conv: FfiReturnConvention) -> impl Display {
fn postlude(ret: &str) -> impl Display {
// When returning a future from Rust to Lua, yield it immediately to the runtime which will
// poll it to completion in the background, then take the fulfilled value once the thread
// gets resumed. Lua user code should never to worry about awaiting futures.
//
// Once the current thread gets resumed and we take the future's fulfilled value, we clear
// the finaliser on the future and forget it (there is nothing to call drop on).
// the finaliser on the future and forget it (there is nothing to drop once the value is
// taken).
//
// `coroutine.yield` is cached as `yield` and `ffi.gc` as `gc` in locals (see lib.rs)
// `coroutine.yield` is cached as `__yield` and `ffi.gc` as `__gc` in locals (see lib.rs)
display!(
"yield({ret}); {ret} = gc({ret}, nil):__take(); {}",
<F::Output as IntoFfi>::postlude(ret, FfiReturnConvention::ByValue)
"__yield({ret}); {ret} = __gc({ret}, nil):__take(); {}",
<F::Output as IntoFfi>::postlude(ret)
)
}
}