Add ctype new support

This commit is contained in:
lumi 2025-06-22 18:41:19 +10:00
parent 0fd59f6874
commit 40478fb7de
Signed by: luaneko
GPG Key ID: 406809B8763FF07A
7 changed files with 118 additions and 81 deletions

7
Cargo.lock generated
View File

@ -812,7 +812,6 @@ dependencies = [
"luaify", "luaify",
"rustc-hash", "rustc-hash",
"simdutf8", "simdutf8",
"static_assertions",
] ]
[[package]] [[package]]
@ -1334,12 +1333,6 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"

View File

@ -12,11 +12,22 @@ pub fn type_id<T: 'static>() -> u64 {
hash.finish() hash.finish()
} }
macro_rules! export {
($($fn:expr),+ $(,)?) => {
// this ensures ffi function symbol exports are actually present in the resulting binary,
// otherwise they may get dead code-eliminated before it reaches the linker
#[used]
static __FFI_EXPORTS: &[fn()] = unsafe {
&[$(::std::mem::transmute($fn as *const ())),*]
};
};
}
macro_rules! display { macro_rules! display {
($($fmt:expr),+) => {{ crate::__internal::disp(move |f| write!(f, $($fmt),+)) }}; ($($fmt:expr),+) => {{ crate::__internal::disp(move |f| write!(f, $($fmt),+)) }};
} }
pub(crate) use display; pub(crate) use {display, export};
pub fn disp(f: impl Fn(&mut Formatter) -> fmt::Result) -> impl Display { pub fn disp(f: impl Fn(&mut Formatter) -> fmt::Result) -> impl Display {
struct Disp<F: Fn(&mut Formatter) -> fmt::Result>(F); struct Disp<F: Fn(&mut Formatter) -> fmt::Result>(F);

View File

@ -1,4 +1,4 @@
use crate::__internal::{disp, display, write_sep}; use crate::__internal::{disp, display, export, write_sep};
pub use luaffi_impl::*; pub use luaffi_impl::*;
use std::{ use std::{
collections::HashSet, collections::HashSet,
@ -31,6 +31,8 @@ unsafe extern "C" fn __is_utf8(ptr: *const u8, len: usize) -> bool {
simdutf8::basic::from_utf8(unsafe { slice::from_raw_parts(ptr, len) }).is_ok() simdutf8::basic::from_utf8(unsafe { slice::from_raw_parts(ptr, len) }).is_ok()
} }
export![__keep, __is_utf8];
const CACHE_LIBS: &[(&str, &str)] = &[ const CACHE_LIBS: &[(&str, &str)] = &[
("table", "table"), ("table", "table"),
("string", "string"), ("string", "string"),
@ -47,7 +49,7 @@ const CACHE_LIBS: &[(&str, &str)] = &[
]; ];
// https://www.lua.org/manual/5.1/manual.html#5.1 // https://www.lua.org/manual/5.1/manual.html#5.1
const CACHE_GLOBALS: &[(&str, &str)] = &[ const CACHE_LOCALS: &[(&str, &str)] = &[
// base // base
("assert", "assert"), ("assert", "assert"),
("error", "error"), ("error", "error"),
@ -86,14 +88,16 @@ const CACHE_GLOBALS: &[(&str, &str)] = &[
("__fmod", "math.fmod"), ("__fmod", "math.fmod"),
// coroutine // coroutine
("__yield", "coroutine.yield"), ("__yield", "coroutine.yield"),
// package
("__preload", "package.preload"),
// debug // debug
("__traceback", "debug.traceback"), ("__traceback", "debug.traceback"),
// ffi // ffi
("__C", "ffi.C"), ("__C", "ffi.C"),
("__ct", "{}"),
("__cdef", "ffi.cdef"), ("__cdef", "ffi.cdef"),
("__cnew", "ffi.new"), ("__new", "ffi.new"),
("__ctype", "ffi.typeof"), ("__typeof", "ffi.typeof"),
("__ctypes", "{}"),
("__istype", "ffi.istype"), ("__istype", "ffi.istype"),
("__metatype", "ffi.metatype"), ("__metatype", "ffi.metatype"),
("__cast", "ffi.cast"), ("__cast", "ffi.cast"),
@ -117,7 +121,7 @@ const CACHE_GLOBALS: &[(&str, &str)] = &[
fn cache_local(f: &mut Formatter, list: &[(&str, &str)]) -> fmt::Result { fn cache_local(f: &mut Formatter, list: &[(&str, &str)]) -> fmt::Result {
write!(f, "local ")?; write!(f, "local ")?;
write_sep(f, ", ", list.iter().map(|(s, _)| s))?; write_sep(f, ", ", list.iter().map(|(s, _)| s))?;
write!(f, "\n = ")?; write!(f, " = ")?;
write_sep(f, ", ", list.iter().map(|(_, s)| s))?; write_sep(f, ", ", list.iter().map(|(_, s)| s))?;
writeln!(f, ";") writeln!(f, ";")
} }
@ -141,7 +145,7 @@ impl Registry {
pub fn include<T: Type>(&mut self) -> &mut Self { pub fn include<T: Type>(&mut self) -> &mut Self {
self.types self.types
.insert(T::name().to_string()) .insert(T::name().to_string())
.then(|| T::build(&mut TypeBuilder::new(self))); .then(|| T::build(&mut TypeBuilder::new::<T>(self)));
self self
} }
@ -149,7 +153,18 @@ impl Registry {
self.include::<T>() self.include::<T>()
.funcs .funcs
.insert(name.to_string()) .insert(name.to_string())
.then(|| writeln!(self.cdef, "{};", T::cdecl(name)).unwrap()); .then(|| writeln!(self.cdef, "{};", T::extern_cdecl(name)).unwrap());
self
}
pub fn preload<T: Type>(&mut self, name: impl Display) -> &mut Self {
self.include::<T>();
writeln!(
self.lua,
r#"__preload["{name}"] = function(...) return __ct.{}(...); end;"#,
T::name()
)
.unwrap();
self self
} }
@ -164,8 +179,8 @@ impl Display for Registry {
let version = env!("CARGO_PKG_VERSION"); let version = env!("CARGO_PKG_VERSION");
writeln!(f, "--- automatically generated by {name} {version}")?; writeln!(f, "--- automatically generated by {name} {version}")?;
cache_local(f, CACHE_LIBS)?; cache_local(f, CACHE_LIBS)?;
cache_local(f, CACHE_GLOBALS)?; cache_local(f, CACHE_LOCALS)?;
writeln!(f, "__cdef [[{}]];", self.cdef)?; writeln!(f, "__cdef [[\n{}\n]];", self.cdef.trim())?;
write!(f, "{}", self.lua) write!(f, "{}", self.lua)
} }
} }
@ -173,6 +188,10 @@ impl Display for Registry {
pub unsafe trait Type { pub unsafe trait Type {
fn name() -> impl Display; fn name() -> impl Display;
fn cdecl(name: impl Display) -> impl Display; fn cdecl(name: impl Display) -> impl Display;
fn extern_cdecl(name: impl Display) -> impl Display {
Self::cdecl(name)
}
fn build(b: &mut TypeBuilder); fn build(b: &mut TypeBuilder);
} }
@ -182,7 +201,10 @@ pub struct TypeBuilder<'r> {
} }
impl<'r> TypeBuilder<'r> { impl<'r> TypeBuilder<'r> {
fn new(registry: &'r mut Registry) -> Self { fn new<T: Type>(registry: &'r mut Registry) -> Self {
let ct = T::name();
let cdecl = T::cdecl("");
writeln!(registry.lua, r#"__ct.{ct} = __typeof("{cdecl}");"#).unwrap();
Self { registry } Self { registry }
} }
@ -283,7 +305,6 @@ pub unsafe trait Metatype {
pub struct MetatypeBuilder<'r> { pub struct MetatypeBuilder<'r> {
registry: &'r mut Registry, registry: &'r mut Registry,
name: String, name: String,
cdecl: String,
cdef: String, cdef: String,
lua: String, lua: String,
} }
@ -293,7 +314,6 @@ impl<'r> MetatypeBuilder<'r> {
Self { Self {
registry, registry,
name: T::Target::name().to_string(), name: T::Target::name().to_string(),
cdecl: T::Target::cdecl("").to_string(),
cdef: String::new(), cdef: String::new(),
lua: r#"do local __mt, __idx = {}, {}; __mt.__index = __idx; "#.into(), lua: r#"do local __mt, __idx = {}, {}; __mt.__index = __idx; "#.into(),
} }
@ -325,7 +345,7 @@ impl<'r> MetatypeBuilder<'r> {
name: impl Display, name: impl Display,
f: impl FnOnce(&mut MetatypeMethodBuilder), f: impl FnOnce(&mut MetatypeMethodBuilder),
) -> &mut Self { ) -> &mut Self {
write!(self.lua, "__mt.{name} = ").unwrap(); write!(self.lua, "__mt.__{name} = ").unwrap();
f(&mut MetatypeMethodBuilder::new(self)); f(&mut MetatypeMethodBuilder::new(self));
write!(self.lua, "; ").unwrap(); write!(self.lua, "; ").unwrap();
self self
@ -342,7 +362,6 @@ impl<'r> Drop for MetatypeBuilder<'r> {
let Self { let Self {
registry, registry,
name, name,
cdecl,
cdef, cdef,
lua, lua,
.. ..
@ -350,12 +369,7 @@ impl<'r> Drop for MetatypeBuilder<'r> {
registry.cdef.push_str(cdef); registry.cdef.push_str(cdef);
registry.lua.push_str(lua); registry.lua.push_str(lua);
writeln!(registry.lua, r#"__metatype(__ct.{name}, __mt); end;"#).unwrap();
writeln!(
registry.lua,
r#"__ctypes.{name} = __metatype("{cdecl}", __mt); end;"#
)
.unwrap();
} }
} }
@ -414,8 +428,6 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
} }
pub fn param<T: FromFfi>(&mut self, name: impl Display) -> &mut Self { pub fn param<T: FromFfi>(&mut self, name: impl Display) -> &mut Self {
self.metatype.registry.include::<T::From>();
(!self.params.is_empty()).then(|| self.params.push_str(", ")); (!self.params.is_empty()).then(|| self.params.push_str(", "));
(!self.args.is_empty()).then(|| self.args.push_str(", ")); (!self.args.is_empty()).then(|| self.args.push_str(", "));
write!(self.params, "{name}").unwrap(); write!(self.params, "{name}").unwrap();
@ -450,6 +462,12 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
self self
} }
pub fn param_ignored(&mut self) -> &mut Self {
(!self.params.is_empty()).then(|| self.params.push_str(", "));
write!(self.params, "_").unwrap();
self
}
pub fn call<T: ToFfi>(&mut self, func: impl Display, ret: FfiReturnConvention) { pub fn call<T: ToFfi>(&mut self, func: impl Display, ret: FfiReturnConvention) {
let Self { let Self {
metatype, metatype,
@ -459,8 +477,6 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
postlude, postlude,
} = self; } = self;
metatype.registry.include::<T::To>();
let lua = &mut metatype.lua; let lua = &mut metatype.lua;
write!(lua, "function({params}) {prelude}").unwrap(); write!(lua, "function({params}) {prelude}").unwrap();
@ -469,21 +485,21 @@ impl<'r, 'm> MetatypeMethodBuilder<'r, 'm> {
write!(lua, "__C.{func}({args}); {postlude}end").unwrap(); write!(lua, "__C.{func}({args}); {postlude}end").unwrap();
} }
FfiReturnConvention::ByValue => { FfiReturnConvention::ByValue => {
let check = T::postlude("res", ret); let check = T::postlude("__res", ret);
write!( write!(
lua, lua,
"local res = __C.{func}({args}); {check}{postlude}return res; end" "local __res = __C.{func}({args}); {check}{postlude}return __res; end"
) )
.unwrap(); .unwrap();
} }
FfiReturnConvention::ByOutParam => { FfiReturnConvention::ByOutParam => {
let ct = T::To::name(); let ct = T::To::name();
let check = T::postlude("res", ret); let check = T::postlude("__res", ret);
write!(lua, "local res = __cnew(__ctypes.{ct}); __C.{func}(res").unwrap(); write!(lua, "local __res = __new(__ct.{ct}); __C.{func}(__res").unwrap();
if !args.is_empty() { if !args.is_empty() {
write!(lua, ", {args}").unwrap(); write!(lua, ", {args}").unwrap();
} }
write!(lua, "); {check}{postlude}return res; end").unwrap() write!(lua, "); {check}{postlude}return __res; end").unwrap()
} }
} }
} }
@ -560,7 +576,7 @@ macro_rules! impl_copy_primitive {
#[allow(unused)] #[allow(unused)]
fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display { fn postlude(ret: &str, conv: FfiReturnConvention) -> impl Display {
disp(move |f| { disp(move |f| Ok({
match conv { match conv {
FfiReturnConvention::Void => unreachable!(), FfiReturnConvention::Void => unreachable!(),
FfiReturnConvention::ByValue => {}, FfiReturnConvention::ByValue => {},
@ -568,9 +584,7 @@ macro_rules! impl_copy_primitive {
// the cdata containing the value and convert it to the equivalent lua value // the cdata containing the value and convert it to the equivalent lua value
FfiReturnConvention::ByOutParam => { $(write!(f, "{ret} = {}; ", $unwrap(ret))?;)? }, FfiReturnConvention::ByOutParam => { $(write!(f, "{ret} = {}; ", $unwrap(ret))?;)? },
} }
}))
Ok(())
})
} }
} }
}; };
@ -592,7 +606,7 @@ impl_copy_primitive!(c_double, "double", "number", |n| display!("tonumber({n})")
unsafe impl<T: Type> Type for *const T { unsafe impl<T: Type> Type for *const T {
fn name() -> impl Display { fn name() -> impl Display {
display!("ptr_const_{}", T::name()) display!("const_{}_ptr", T::name())
} }
fn cdecl(name: impl Display) -> impl Display { fn cdecl(name: impl Display) -> impl Display {
@ -606,7 +620,7 @@ unsafe impl<T: Type> Type for *const T {
unsafe impl<T: Type> Type for *mut T { unsafe impl<T: Type> Type for *mut T {
fn name() -> impl Display { fn name() -> impl Display {
display!("ptr_mut_{}", T::name()) display!("{}_ptr", T::name())
} }
fn cdecl(name: impl Display) -> impl Display { fn cdecl(name: impl Display) -> impl Display {
@ -684,7 +698,7 @@ unsafe impl<T: Type> ToFfi for *mut T {
// //
unsafe impl<T: Type> Type for &T { unsafe impl<T: Type> Type for &T {
fn name() -> impl Display { fn name() -> impl Display {
display!("ref_const_{}", T::name()) display!("const_{}_ptr", T::name())
} }
fn cdecl(name: impl Display) -> impl Display { fn cdecl(name: impl Display) -> impl Display {
@ -698,7 +712,7 @@ unsafe impl<T: Type> Type for &T {
unsafe impl<T: Type> Type for &mut T { unsafe impl<T: Type> Type for &mut T {
fn name() -> impl Display { fn name() -> impl Display {
display!("ref_mut_{}", T::name()) display!("{}_ptr", T::name())
} }
fn cdecl(name: impl Display) -> impl Display { fn cdecl(name: impl Display) -> impl Display {
@ -782,7 +796,7 @@ unsafe impl<T: Type> FromFfi for &mut T {
// //
unsafe impl<T: Type> Type for [T] { unsafe impl<T: Type> Type for [T] {
fn name() -> impl Display { fn name() -> impl Display {
display!("arr_{}", T::name()) display!("{}_arr", T::name())
} }
fn cdecl(name: impl Display) -> impl Display { fn cdecl(name: impl Display) -> impl Display {
@ -796,7 +810,7 @@ unsafe impl<T: Type> Type for [T] {
unsafe impl<T: Type, const N: usize> Type for [T; N] { unsafe impl<T: Type, const N: usize> Type for [T; N] {
fn name() -> impl Display { fn name() -> impl Display {
display!("arr{N}_{}", T::name()) display!("{}_arr{N}", T::name())
} }
fn cdecl(name: impl Display) -> impl Display { fn cdecl(name: impl Display) -> impl Display {
@ -824,20 +838,29 @@ macro_rules! impl_function {
// //
unsafe impl<$($arg: Type,)* $ret: Type> Type for $($type)+ { unsafe impl<$($arg: Type,)* $ret: Type> Type for $($type)+ {
fn name() -> impl Display { fn name() -> impl Display {
disp(|f| { disp(|f| Ok({
write!(f, "fn")?; write!(f, "fn_{}", $ret::name())?;
$(write!(f, "_{}", $arg::name())?;)* $(write!(f, "_{}", $arg::name())?;)*
write!(f, "_{}", $ret::name()) }))
})
} }
fn cdecl(name: impl Display) -> impl Display { fn cdecl(name: impl Display) -> impl Display {
$ret::cdecl(disp(move |f| { $ret::cdecl(disp(move |f| Ok({
let mut _n = 0; let mut _n = 0;
write!(f, "(*{name})(")?; write!(f, "(*{name})(")?;
$(if _n != 0 { write!(f, ", ")?; } write!(f, "{}", $arg::cdecl(""))?; _n += 1;)* $(if _n != 0 { write!(f, ", ")?; } write!(f, "{}", $arg::cdecl(""))?; _n += 1;)*
write!(f, ")") write!(f, ")")?;
})) })))
}
fn extern_cdecl(name: impl Display) -> impl Display {
$ret::cdecl(disp(move |f| Ok({
// for top-level function declarations in cdef
let mut _n = 0;
write!(f, "{name}(")?;
$(if _n != 0 { write!(f, ", ")?; } write!(f, "{}", $arg::cdecl(""))?; _n += 1;)*
write!(f, ")")?;
})))
} }
fn build(b: &mut TypeBuilder) { fn build(b: &mut TypeBuilder) {

View File

@ -39,7 +39,7 @@ unsafe impl<T: FromFfi> FromFfi for Option<T> {
fn prelude(arg: &str) -> impl Display { fn prelude(arg: &str) -> impl Display {
let ct = Self::From::name(); let ct = Self::From::name();
display!( display!(
"if {arg} == nil then {arg} = __cnew(__ctypes.{ct}); else {}{arg} = __cnew(__ctypes.{ct}, 1, {arg}); end; ", "if {arg} == nil then {arg} = __new(__ct.{ct}); else {}{arg} = __new(__ct.{ct}, 1, {arg}); end; ",
T::prelude(arg) T::prelude(arg)
) )
} }

View File

@ -5,17 +5,12 @@ use std::{fmt, ptr, slice};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
#[cdef] #[cdef]
pub struct lua_buf { pub struct lua_buf {
__ptr: *mut u8, __ptr: *const u8,
__len: usize, __len: usize,
} }
#[metatype] #[metatype]
impl lua_buf { impl lua_buf {}
#[new]
extern "Lua-C" fn new() -> u32 {
todo!()
}
}
unsafe impl FromFfi for *const [u8] { unsafe impl FromFfi for *const [u8] {
type From = lua_buf; type From = lua_buf;
@ -33,7 +28,7 @@ unsafe impl FromFfi for *const [u8] {
f, f,
r#"if {arg} ~= nil then assert(type({arg}) == "string", "string expected in argument '{arg}', got " .. type({arg})); "# r#"if {arg} ~= nil then assert(type({arg}) == "string", "string expected in argument '{arg}', got " .. type({arg})); "#
)?; )?;
write!(f, "{arg} = __cnew(__ctypes.{ct}, {arg}, #{arg}); end; ") write!(f, "{arg} = __new(__ct.{ct}, {arg}, #{arg}); end; ")
}) })
} }
@ -69,7 +64,7 @@ unsafe impl FromFfi for &str {
f, f,
r#"assert(__C.{IS_UTF8_FN}({arg}, #{arg}), "argument '{arg}' must be a valid utf-8 string"); "# r#"assert(__C.{IS_UTF8_FN}({arg}, #{arg}), "argument '{arg}' must be a valid utf-8 string"); "#
)?; )?;
write!(f, "{arg} = __cnew(__ctypes.{ct}, {arg}, #{arg}); ") write!(f, "{arg} = __new(__ct.{ct}, {arg}, #{arg}); ")
}) })
} }

View File

@ -44,6 +44,17 @@ fn generate_impls(imp: &mut ItemImpl) -> Result<TokenStream> {
.map(generate_ffi_register) .map(generate_ffi_register)
.collect::<Result<_>>()?; .collect::<Result<_>>()?;
let ffi_new_fallback = match ffi_funcs
.iter()
.find(|f| f.attrs.metatable.as_deref() == Some("new"))
{
Some(_) => None,
None => Some({
let err = format!(r#"function() error("type '{ty_name}' has no constructor"); end"#);
quote! { b.metatable_raw("new", #err); }
}),
};
let ffi_drop_rname = format_ident!("__ffi_drop"); let ffi_drop_rname = format_ident!("__ffi_drop");
let ffi_drop_cname = format!("{ty_name}_drop"); let ffi_drop_cname = format!("{ty_name}_drop");
@ -78,6 +89,8 @@ fn generate_impls(imp: &mut ItemImpl) -> Result<TokenStream> {
#(#ffi_register)* #(#ffi_register)*
#(#lua_register)* #(#lua_register)*
#ffi_new_fallback
b.declare::<unsafe extern "C" fn(*mut Self)>(#ffi_drop_cname); b.declare::<unsafe extern "C" fn(*mut Self)>(#ffi_drop_cname);
b.metatable_raw("gc", ::std::format_args!("__C.{}", #ffi_drop_cname)); b.metatable_raw("gc", ::std::format_args!("__C.{}", #ffi_drop_cname));
} }
@ -100,7 +113,7 @@ struct FfiFunction {
#[derive(Default)] #[derive(Default)]
struct FfiFunctionAttrs { struct FfiFunctionAttrs {
metatable: Option<LitStr>, metatable: Option<String>,
} }
fn get_ffi_functions(imp: &mut ItemImpl) -> Result<Vec<FfiFunction>> { fn get_ffi_functions(imp: &mut ItemImpl) -> Result<Vec<FfiFunction>> {
@ -161,11 +174,11 @@ fn parse_ffi_function_attrs(attrs: &mut Vec<Attribute>) -> Result<FfiFunctionAtt
while let Some(attr) = attrs.get(i) { while let Some(attr) = attrs.get(i) {
if let Some(name) = attr.path().get_ident() { if let Some(name) = attr.path().get_ident() {
if name == "metatable" { if name == "metatable" {
parsed.metatable = attr.parse_args()?; parsed.metatable = Some(attr.parse_args::<LitStr>()?.value());
attrs.remove(i); attrs.remove(i);
continue; continue;
} else if name == "new" { } else if name == "new" {
parsed.metatable = parse_quote!("new"); parsed.metatable = Some("new".into());
attrs.remove(i); attrs.remove(i);
continue; continue;
} }
@ -194,7 +207,7 @@ fn generate_ffi_wrapper(func: &FfiFunction) -> Result<TokenStream> {
let mut args = vec![]; let mut args = vec![];
for (i, param) in func.params.iter().enumerate() { for (i, param) in func.params.iter().enumerate() {
let name = format_ident!("__arg{i}"); let name = format_ident!("arg{i}");
let ty = &param.ty; let ty = &param.ty;
match get_ffi_arg_type(ty) { match get_ffi_arg_type(ty) {
@ -208,10 +221,10 @@ fn generate_ffi_wrapper(func: &FfiFunction) -> Result<TokenStream> {
let (ret, call) = if func.ret_by_out { let (ret, call) = if func.ret_by_out {
// make return by out-param the first parameter // make return by out-param the first parameter
let ret = &func.ret; let ret = &func.ret;
params.insert(0, quote! { __out: *mut #ret }); params.insert(0, quote! { out: *mut #ret });
( (
quote!(()), quote!(()),
quote! { ::std::ptr::write(__out, Self::#name(#(#args),*)) }, quote! { ::std::ptr::write(out, Self::#name(#(#args),*)) },
) )
} else { } else {
let ret = &func.ret; let ret = &func.ret;
@ -220,9 +233,7 @@ fn generate_ffi_wrapper(func: &FfiFunction) -> Result<TokenStream> {
Ok(quote! { Ok(quote! {
#[unsafe(export_name = #c_name)] #[unsafe(export_name = #c_name)]
unsafe extern "C" fn #rust_name(#(#params),*) -> #ret { unsafe extern "C" fn #rust_name(#(#params),*) -> #ret { unsafe { #call } }
unsafe { #call }
}
}) })
} }
@ -234,6 +245,11 @@ fn generate_ffi_register(func: &FfiFunction) -> Result<TokenStream> {
let mut params = vec![]; let mut params = vec![];
let mut register = vec![]; let mut register = vec![];
// for __new metamethods, ignore the first argument (ctype of self)
if func.attrs.metatable.as_deref() == Some("new") {
register.push(quote! { b.param_ignored(); });
}
for param in func.params.iter() { for param in func.params.iter() {
let name = format!("{}", pat_ident(&param.pat)?); let name = format!("{}", pat_ident(&param.pat)?);
let ty = &param.ty; let ty = &param.ty;
@ -255,8 +271,10 @@ fn generate_ffi_register(func: &FfiFunction) -> Result<TokenStream> {
quote! { #ffi::FfiReturnConvention::ByValue } quote! { #ffi::FfiReturnConvention::ByValue }
}; };
let declare = quote! { let declare = if func.ret_by_out {
b.declare::<unsafe extern "C" fn(#(#params),*) -> #ret>(#c_name); quote! { b.declare::<unsafe extern "C" fn(*mut #ret, #(#params),*)>(#c_name); }
} else {
quote! { b.declare::<unsafe extern "C" fn(#(#params),*) -> #ret>(#c_name); }
}; };
let register = match func.attrs.metatable { let register = match func.attrs.metatable {
@ -274,10 +292,7 @@ fn generate_ffi_register(func: &FfiFunction) -> Result<TokenStream> {
}, },
}; };
Ok(quote! { Ok(quote! { #declare #register })
#declare
#register
})
} }
fn generate_ffi_exports<'a>( fn generate_ffi_exports<'a>(

View File

@ -136,7 +136,7 @@ fn init_vm(_args: &Args) -> luajit::State {
luajit::State::new().unwrap_or_else(|err| panic!("failed to initialise runtime: {err}")); luajit::State::new().unwrap_or_else(|err| panic!("failed to initialise runtime: {err}"));
let mut registry = luaffi::Registry::new(); let mut registry = luaffi::Registry::new();
registry.include::<lb_core::lb_core>(); registry.preload::<lb_core::lb_core>("lb:core");
println!("{registry}"); println!("{registry}");