Implement the foundations for annotation generation
This commit is contained in:
@@ -32,7 +32,7 @@ pub fn transform(args: Args, mut item: Item) -> Result<TokenStream> {
|
||||
|
||||
let mod_name = format_ident!("__{name}_cdef");
|
||||
|
||||
Ok(quote_spanned!(name.span() =>
|
||||
Ok(quote!(
|
||||
#[repr(C)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#item
|
||||
@@ -51,10 +51,9 @@ pub fn transform(args: Args, mut item: Item) -> Result<TokenStream> {
|
||||
|
||||
fn generate_type(ty: &Ident) -> Result<TokenStream> {
|
||||
let ffi = ffi_crate();
|
||||
let span = ty.span();
|
||||
let name = LitStr::new(&ty.unraw().to_string(), span);
|
||||
let name = ty.unraw().to_string();
|
||||
|
||||
Ok(quote_spanned!(span =>
|
||||
Ok(quote!(
|
||||
unsafe impl #ffi::Type for #ty {
|
||||
fn name() -> impl ::std::fmt::Display { #name }
|
||||
|
||||
@@ -71,6 +70,10 @@ fn generate_type(ty: &Ident) -> Result<TokenStream> {
|
||||
}
|
||||
}
|
||||
|
||||
impl #ffi::Annotation for #ty {
|
||||
fn annotation() -> impl ::std::fmt::Display { #name }
|
||||
}
|
||||
|
||||
// SAFETY: we can always implement `IntoFfi` because it transfers ownership from Rust to Lua
|
||||
unsafe impl #ffi::IntoFfi for #ty {
|
||||
type Into = Self;
|
||||
@@ -82,7 +85,7 @@ fn generate_type(ty: &Ident) -> Result<TokenStream> {
|
||||
fn generate_module(name: &str, ty: &Ident) -> Result<TokenStream> {
|
||||
let ffi = ffi_crate();
|
||||
|
||||
Ok(quote_spanned!(ty.span() =>
|
||||
Ok(quote!(
|
||||
impl #ffi::Module for #ty {
|
||||
fn name() -> impl ::std::fmt::Display { #name }
|
||||
}
|
||||
@@ -98,10 +101,9 @@ fn generate_cdef_structure(str: &mut ItemStruct) -> Result<TokenStream> {
|
||||
|
||||
let ffi = ffi_crate();
|
||||
let ty = &str.ident;
|
||||
let span = ty.span();
|
||||
let build = generate_cdef_build(&get_cfields(&mut str.fields)?)?;
|
||||
|
||||
Ok(quote_spanned!(span =>
|
||||
Ok(quote!(
|
||||
unsafe impl #ffi::Cdef for #ty {
|
||||
fn build(b: &mut #ffi::CdefBuilder) { #build }
|
||||
}
|
||||
@@ -117,18 +119,16 @@ fn generate_cdef_enum(enu: &mut ItemEnum) -> Result<TokenStream> {
|
||||
|
||||
let ffi = ffi_crate();
|
||||
let ty = &enu.ident;
|
||||
let span = ty.span();
|
||||
let build = enu
|
||||
.variants
|
||||
.iter_mut()
|
||||
.map(|variant| {
|
||||
let span = variant.span();
|
||||
let build = generate_cdef_build(&get_cfields(&mut variant.fields)?)?;
|
||||
Ok(quote_spanned!(span => b.inner_struct(|b| { #build })))
|
||||
Ok(quote!(b.inner_struct(|b| { #build })))
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
Ok(quote_spanned!(span =>
|
||||
Ok(quote!(
|
||||
unsafe impl #ffi::Cdef for #ty {
|
||||
fn build(b: &mut #ffi::CdefBuilder) {
|
||||
b.field::<::std::ffi::c_int>("__tag").inner_union(|b| { #(#build;)* });
|
||||
@@ -201,7 +201,7 @@ fn generate_cdef_build(fields: &[CField]) -> Result<TokenStream> {
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
let ty = &field.ty;
|
||||
let offset = offset(i);
|
||||
body.push(quote_spanned!(ty.span() =>
|
||||
body.push(quote!(
|
||||
// round up current offset to the alignment of field type for field offset
|
||||
offset = (offset + #align_of::<#ty>() - 1) & !(#align_of::<#ty>() - 1);
|
||||
align = #max(align, #align_of::<#ty>());
|
||||
|
||||
@@ -21,7 +21,7 @@ pub fn transform(args: Args, mut imp: ItemImpl) -> Result<TokenStream> {
|
||||
let impls = generate_impls(&args, &mut imp)?;
|
||||
let mod_name = format_ident!("__{}_metatype", ty_name(&imp.self_ty)?);
|
||||
|
||||
Ok(quote_spanned!(imp.self_ty.span() =>
|
||||
Ok(quote!(
|
||||
#imp
|
||||
|
||||
#[doc(hidden)]
|
||||
@@ -119,7 +119,7 @@ fn generate_impls(_args: &Args, imp: &mut ItemImpl) -> Result<TokenStream> {
|
||||
let build = ®istry.build;
|
||||
let exports = generate_ffi_exports(®istry)?;
|
||||
|
||||
Ok(quote_spanned!(ty.span() =>
|
||||
Ok(quote!(
|
||||
impl #ty { #(#shims)* }
|
||||
|
||||
unsafe impl #ffi::Metatype for #ty {
|
||||
@@ -219,10 +219,10 @@ impl ToTokens for Metamethod {
|
||||
|
||||
struct FfiFunction {
|
||||
name: Ident,
|
||||
is_async: bool,
|
||||
params: Vec<PatType>,
|
||||
params: Vec<(Ident, Type)>,
|
||||
ret: Type,
|
||||
attrs: FfiFunctionAttrs,
|
||||
is_async: bool,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -251,30 +251,31 @@ fn get_ffi_functions(imp: &mut ItemImpl) -> Result<Vec<FfiFunction>> {
|
||||
.sig
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|arg| match arg {
|
||||
FnArg::Receiver(recv) => {
|
||||
let ty = &recv.ty;
|
||||
parse_quote_spanned!(ty.span() => self: #ty)
|
||||
}
|
||||
FnArg::Typed(ty) => ty.clone(),
|
||||
.map(|arg| {
|
||||
Ok(match arg {
|
||||
FnArg::Receiver(recv) => {
|
||||
(Ident::new("self", recv.span()), (*recv.ty).clone())
|
||||
}
|
||||
FnArg::Typed(ty) => (pat_ident(&ty.pat)?.clone(), (*ty.ty).clone()),
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
let ret = match func.sig.output {
|
||||
ReturnType::Default => parse_quote!(()),
|
||||
ReturnType::Type(_, ref ty) => (**ty).clone(),
|
||||
};
|
||||
|
||||
for param in params.iter() {
|
||||
// double underscores are reserved for generated glue code
|
||||
for (name, ty) in params.iter() {
|
||||
// double underscores are reserved for glue code
|
||||
syn_assert!(
|
||||
!pat_ident(¶m.pat)?.to_string().starts_with("__"),
|
||||
param.pat,
|
||||
!name.to_string().starts_with("__"),
|
||||
name,
|
||||
"parameter names should not start with `__`"
|
||||
);
|
||||
|
||||
// lifetime should be determined by the caller (lua)
|
||||
if let Type::Reference(ref ty) = *param.ty {
|
||||
// lifetime should be determined by the caller (which is lua)
|
||||
if let Type::Reference(ty) = ty {
|
||||
syn_assert!(
|
||||
ty.lifetime.is_none(),
|
||||
ty.lifetime,
|
||||
@@ -290,10 +291,10 @@ fn get_ffi_functions(imp: &mut ItemImpl) -> Result<Vec<FfiFunction>> {
|
||||
|
||||
funcs.push(FfiFunction {
|
||||
name: func.sig.ident.clone(),
|
||||
is_async: func.sig.asyncness.is_some(),
|
||||
params,
|
||||
ret,
|
||||
attrs,
|
||||
is_async: func.sig.asyncness.is_some(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -387,16 +388,8 @@ fn add_ffi_function(registry: &mut Registry, func: &FfiFunction) -> Result<()> {
|
||||
let func_params = &func.params; // target function parameters
|
||||
let func_ret = &func.ret; // target function return type
|
||||
let mut func_args = vec![]; // target function arguments
|
||||
|
||||
let mut shim_params = vec![]; // shim function parameters
|
||||
let mut shim_ret = if func.is_async {
|
||||
// shim function return type
|
||||
quote_spanned!(func_ret.span() => #ffi::future::lua_future<impl ::std::future::Future<Output = #func_ret>>)
|
||||
} else {
|
||||
quote_spanned!(func_ret.span() => <#func_ret as #ffi::IntoFfi>::Into)
|
||||
};
|
||||
|
||||
let mut asserts = vec![]; // compile-time builder asserts
|
||||
let mut asserts = vec![]; // compile-time asserts
|
||||
let mut build = vec![]; // ffi builder body
|
||||
|
||||
// for __new metamethods, ignore the first argument (ctype of self, for which there is no
|
||||
@@ -407,99 +400,102 @@ fn add_ffi_function(registry: &mut Registry, func: &FfiFunction) -> Result<()> {
|
||||
));
|
||||
}
|
||||
|
||||
for (i, param) in func_params.iter().enumerate() {
|
||||
let func_param = ¶m.ty;
|
||||
for (i, (name, func_param)) in func_params.iter().enumerate() {
|
||||
let span = func_param.span();
|
||||
let name = name.unraw().to_string();
|
||||
let shim_param = format_ident!("arg{i}");
|
||||
let name = pat_ident(¶m.pat)?.unraw().to_string();
|
||||
|
||||
match get_ffi_param_type(func_param) {
|
||||
FfiParameterType::Default => {
|
||||
shim_params.push(quote_spanned!(func_param.span() =>
|
||||
shim_params.push(quote_spanned!(span =>
|
||||
#shim_param: <#func_param as #ffi::FromFfi>::From
|
||||
));
|
||||
func_args.push(quote_spanned!(param.pat.span() =>
|
||||
func_args.push(quote_spanned!(span =>
|
||||
<#func_param as #ffi::FromFfi>::convert(#shim_param)
|
||||
));
|
||||
build.push(quote_spanned!(param.pat.span() =>
|
||||
build.push(quote_spanned!(span =>
|
||||
b.param::<#func_param>(#name);
|
||||
));
|
||||
}
|
||||
ty @ (FfiParameterType::StringLike(str) | FfiParameterType::OptionStringLike(str)) => {
|
||||
let shim_param_len = format_ident!("arg{i}_len");
|
||||
shim_params.push(quote_spanned!(func_param.span() =>
|
||||
shim_params.push(quote_spanned!(span =>
|
||||
#shim_param: ::std::option::Option<&::std::primitive::u8>,
|
||||
#shim_param_len: ::std::primitive::usize
|
||||
));
|
||||
let allow_nil = matches!(ty, FfiParameterType::OptionStringLike(_));
|
||||
let check_utf8 = matches!(str, StringLike::Str);
|
||||
let mut func_arg = quote_spanned!(func_param.span() =>
|
||||
let mut func_arg = quote_spanned!(span =>
|
||||
#shim_param.map(|s| ::std::slice::from_raw_parts(s, #shim_param_len))
|
||||
);
|
||||
func_arg = match str {
|
||||
StringLike::SliceU8 => func_arg,
|
||||
StringLike::BStr => {
|
||||
quote_spanned!(func_param.span() => #func_arg.map(::bstr::BStr::new))
|
||||
quote_spanned!(span => #func_arg.map(::bstr::BStr::new))
|
||||
}
|
||||
StringLike::Str => {
|
||||
quote_spanned!(func_param.span() => #func_arg.map(|s| {
|
||||
quote_spanned!(span => #func_arg.map(|s| {
|
||||
::std::debug_assert!(::std::str::from_utf8(s).is_ok());
|
||||
::std::str::from_utf8_unchecked(s)
|
||||
}))
|
||||
}
|
||||
};
|
||||
if !allow_nil {
|
||||
func_arg = quote_spanned!(func_param.span() => {
|
||||
func_arg = quote_spanned!(span => {
|
||||
let arg = #func_arg;
|
||||
::std::debug_assert!(arg.is_some());
|
||||
arg.unwrap_unchecked()
|
||||
});
|
||||
}
|
||||
func_args.push(func_arg);
|
||||
build.push(quote_spanned!(param.pat.span() =>
|
||||
build.push(quote_spanned!(span =>
|
||||
b.param_str(#name, #allow_nil, #check_utf8);
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// shim function body
|
||||
let mut shim_body = if func.is_async {
|
||||
// for async functions, wrapped the returned future in lua_future
|
||||
quote_spanned!(func_name.span() => #ffi::future::lua_future::new(Self::#func_name(#(#func_args),*)))
|
||||
} else {
|
||||
quote_spanned!(func_name.span() => <#func_ret as #ffi::IntoFfi>::convert(Self::#func_name(#(#func_args),*)))
|
||||
};
|
||||
let func_call = quote!(Self::#func_name(#(#func_args),*)); // target function call
|
||||
|
||||
if !func.is_async {
|
||||
// shim function body and return type
|
||||
let (shim_body, shim_ret) = if func.is_async {
|
||||
let span = func_ret.span();
|
||||
(
|
||||
// for async functions, wrapped the returned future in lua_future
|
||||
quote_spanned!(span => #ffi::future::lua_future::new(#func_call)),
|
||||
quote_spanned!(span => #ffi::future::lua_future<impl ::std::future::Future<Output = #func_ret>>),
|
||||
)
|
||||
} else {
|
||||
let span = func_ret.span();
|
||||
match get_ffi_ret_type(&func_ret) {
|
||||
FfiReturnType::Void => {
|
||||
asserts.push(quote_spanned!(func_ret.span() =>
|
||||
asserts.push(quote_spanned!(span =>
|
||||
<<#func_ret as #ffi::IntoFfi>::Into as #ffi::Type>::ty() == #ffi::TypeType::Void
|
||||
));
|
||||
(func_call, quote_spanned!(span => ()))
|
||||
}
|
||||
FfiReturnType::ByValue => {
|
||||
asserts.push(quote_spanned!(func_ret.span() =>
|
||||
asserts.push(quote_spanned!(span =>
|
||||
<#func_ret as #ffi::IntoFfi>::convention() == #ffi::FfiReturnConvention::ByValue
|
||||
));
|
||||
(
|
||||
quote_spanned!(span => <#func_ret as #ffi::IntoFfi>::convert(#func_call)),
|
||||
quote_spanned!(span => <#func_ret as #ffi::IntoFfi>::Into),
|
||||
)
|
||||
}
|
||||
FfiReturnType::ByOutParam => {
|
||||
asserts.push(quote_spanned!(func_ret.span() =>
|
||||
asserts.push(quote_spanned!(span =>
|
||||
<#func_ret as #ffi::IntoFfi>::convention() == #ffi::FfiReturnConvention::ByOutParam
|
||||
));
|
||||
|
||||
shim_params.insert(0, quote_spanned!(func_ret.span() => out: *mut #shim_ret));
|
||||
|
||||
(shim_body, shim_ret) = (
|
||||
quote_spanned!(func_ret.span() => ::std::ptr::write(out, #shim_body)),
|
||||
quote_spanned!(func_ret.span() => ()),
|
||||
);
|
||||
let out = quote_spanned!(span => out: *mut <#func_ret as #ffi::IntoFfi>::Into);
|
||||
shim_params.insert(0, out);
|
||||
(
|
||||
quote_spanned!(span => ::std::ptr::write(out, <#func_ret as #ffi::IntoFfi>::convert(#func_call))),
|
||||
quote_spanned!(span => ()),
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// build.push(quote_spanned!(func_name.span() =>
|
||||
// b.call_inferred(#c_name, Self::#func_name);
|
||||
// ));
|
||||
}
|
||||
};
|
||||
|
||||
build.push({
|
||||
let infer_args = iter::repeat_n(quote!(::std::unreachable!()), func_params.len());
|
||||
@@ -508,23 +504,16 @@ fn add_ffi_function(registry: &mut Registry, func: &FfiFunction) -> Result<()> {
|
||||
} else {
|
||||
quote!(|| Self::#func_name(#(#infer_args),*))
|
||||
};
|
||||
quote_spanned!(func_name.span() => b.call_inferred(#c_name, #infer);)
|
||||
quote!(b.call_inferred(#c_name, #infer);)
|
||||
});
|
||||
|
||||
registry.build.push(quote_spanned!(func_name.span() =>
|
||||
#(::std::assert!(#asserts);)*
|
||||
));
|
||||
|
||||
registry.build.push(quote!(#(::std::assert!(#asserts);)*));
|
||||
registry.build.push(match func.attrs.metamethod {
|
||||
Some(ref mm) => quote_spanned!(func_name.span() =>
|
||||
b.metatable(#mm, |b| { #(#build)* });
|
||||
),
|
||||
None => quote_spanned!(func_name.span() =>
|
||||
b.index(#lua_name, |b| { #(#build)* });
|
||||
),
|
||||
Some(ref mm) => quote!(b.metatable(#mm, |b| { #(#build)* });),
|
||||
None => quote!(b.index(#lua_name, |b| { #(#build)* });),
|
||||
});
|
||||
|
||||
registry.shims.push(parse_quote_spanned!(func_name.span() =>
|
||||
registry.shims.push(parse_quote!(
|
||||
#[unsafe(export_name = #c_name)]
|
||||
unsafe extern "C" fn #shim_name(#(#shim_params),*) -> #shim_ret { unsafe { #shim_body } }
|
||||
));
|
||||
@@ -536,7 +525,7 @@ fn generate_ffi_exports(registry: &Registry) -> Result<TokenStream> {
|
||||
let ty = ®istry.ty;
|
||||
let names = registry.shims.iter().map(|f| &f.sig.ident);
|
||||
|
||||
Ok(quote_spanned!(ty.span() =>
|
||||
Ok(quote!(
|
||||
// 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]
|
||||
@@ -583,18 +572,14 @@ fn get_lua_functions(imp: &mut ItemImpl) -> Result<Vec<LuaFunction>> {
|
||||
.sig
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
Ok(match arg {
|
||||
FnArg::Receiver(recv) => Pat::Type(parse_quote_spanned!(recv.span() =>
|
||||
self: cdata
|
||||
)),
|
||||
FnArg::Typed(ty) => Pat::Type(ty.clone()),
|
||||
})
|
||||
.map(|arg| match arg {
|
||||
FnArg::Receiver(recv) => parse_quote_spanned!(recv.span() => self),
|
||||
FnArg::Typed(ty) => (*ty.pat).clone(), // ignore parameter type (only used for documentation purposes)
|
||||
})
|
||||
.collect::<Result<_>>()?;
|
||||
.collect();
|
||||
|
||||
if let Some(ref variadic) = func.sig.variadic {
|
||||
params.push(parse_quote_spanned!(variadic.span() => variadic!()));
|
||||
params.push(parse_quote_spanned!(variadic.span() => variadic!())); // luaify builtin macro
|
||||
}
|
||||
|
||||
let attrs = parse_lua_function_attrs(&mut func.attrs)?;
|
||||
@@ -625,62 +610,45 @@ fn stub_lua_function(func: &mut ImplItemFn) -> Result<()> {
|
||||
func.attrs.push(parse_quote!(#[allow(unused)]));
|
||||
func.block.stmts.clear();
|
||||
func.block.stmts.push(parse_quote!(
|
||||
::std::unreachable!("cannot call lua function from rust");
|
||||
const fn has_annotation<T: #ffi::Annotation>() {}
|
||||
));
|
||||
|
||||
let inputs = &mut func.sig.inputs;
|
||||
let output = &mut func.sig.output;
|
||||
|
||||
for input in inputs.iter_mut() {
|
||||
if let FnArg::Typed(pat) = input
|
||||
&& let Ok(stub) = stub_lua_type(&pat.ty)
|
||||
{
|
||||
pat.ty = stub.into();
|
||||
}
|
||||
}
|
||||
|
||||
if let ReturnType::Type(_, ty) = output
|
||||
&& let Ok(stub) = stub_lua_type(ty)
|
||||
{
|
||||
*ty = stub.into();
|
||||
}
|
||||
|
||||
// convert `...` variadic to a `rest: luaffi::marker::Many` parameter
|
||||
if let Some(ref variadic) = func.sig.variadic {
|
||||
let ty = quote_spanned!(variadic.span() => variadic);
|
||||
inputs.push(parse_quote!(rest: #ffi::__internal::stub_types::#ty));
|
||||
let param = Ident::new("rest", variadic.span());
|
||||
let ty = quote_spanned!(variadic.span() => many);
|
||||
func.sig.variadic = None;
|
||||
func.sig
|
||||
.inputs
|
||||
.push(parse_quote!(#param: #ffi::marker::#ty));
|
||||
}
|
||||
|
||||
for param in func.sig.inputs.iter() {
|
||||
let ty = match param {
|
||||
FnArg::Receiver(recv) => &recv.ty,
|
||||
FnArg::Typed(ty) => &ty.ty,
|
||||
};
|
||||
|
||||
// temporary assertion until we implement annotation generation
|
||||
func.block.stmts.push(parse_quote!(
|
||||
has_annotation::<#ty>();
|
||||
));
|
||||
}
|
||||
|
||||
// temporary assertion until we implement annotation generation
|
||||
if let ReturnType::Type(_, ref ty) = func.sig.output {
|
||||
func.block.stmts.push(parse_quote!(
|
||||
has_annotation::<#ty>();
|
||||
));
|
||||
}
|
||||
|
||||
func.block.stmts.push(parse_quote!(
|
||||
::std::unreachable!(r#"cannot call extern "Lua" function from rust"#);
|
||||
));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stub_lua_type(ty: &Type) -> Result<Type> {
|
||||
let ffi = ffi_crate();
|
||||
let span = ty.span();
|
||||
let ty = if let Type::Infer(_) = ty {
|
||||
quote_spanned!(span => any)
|
||||
} else {
|
||||
match ty_name(ty)?.to_string().as_str() {
|
||||
"any" => quote_spanned!(span => any),
|
||||
"many" => quote_spanned!(span => many),
|
||||
"nil" => quote_spanned!(span => nil),
|
||||
"boolean" => quote_spanned!(span => boolean),
|
||||
"lightuserdata" => quote_spanned!(span => lightuserdata),
|
||||
"number" => quote_spanned!(span => number),
|
||||
"integer" => quote_spanned!(span => integer),
|
||||
"string" => quote_spanned!(span => string),
|
||||
"table" => quote_spanned!(span => table),
|
||||
"function" => quote_spanned!(span => function),
|
||||
"userdata" => quote_spanned!(span => userdata),
|
||||
"thread" => quote_spanned!(span => thread),
|
||||
"cdata" => quote_spanned!(span => cdata),
|
||||
_ => syn_error!(ty, "unknown lua type"),
|
||||
}
|
||||
};
|
||||
|
||||
Ok(parse_quote!(#ffi::__internal::stub_types::#ty))
|
||||
}
|
||||
|
||||
fn parse_lua_function_attrs(attrs: &mut Vec<Attribute>) -> Result<LuaFunctionAttrs> {
|
||||
let mut parsed = LuaFunctionAttrs::default();
|
||||
let mut i = 0;
|
||||
@@ -707,12 +675,8 @@ fn add_lua_function(registry: &mut Registry, func: &LuaFunction) -> Result<()> {
|
||||
let name = func_name.unraw().to_string();
|
||||
|
||||
registry.build.push(match func.attrs.metamethod {
|
||||
Some(ref mm) => quote_spanned!(func_name.span() =>
|
||||
b.metatable_raw(#mm, #luaify(|#(#params),*| #body));
|
||||
),
|
||||
None => quote_spanned!(func_name.span() =>
|
||||
b.index_raw(#name, #luaify(|#(#params),*| #body));
|
||||
),
|
||||
Some(ref mm) => quote!(b.metatable_raw(#mm, #luaify(|#(#params),*| #body));),
|
||||
None => quote!(b.index_raw(#name, #luaify(|#(#params),*| #body));),
|
||||
});
|
||||
|
||||
Ok(())
|
||||
@@ -747,46 +711,36 @@ fn inject_merged_drop(registry: &mut Registry, lua: Option<&LuaFunction>) -> Res
|
||||
"finaliser must take exactly one parameter"
|
||||
);
|
||||
|
||||
match lua.params[0] {
|
||||
// should be `self: cdata` PatType
|
||||
Pat::Type(ref ty) => {
|
||||
syn_assert!(
|
||||
pat_ident(&ty.pat)? == "self",
|
||||
lua.params[0],
|
||||
"finaliser parameter must be `self`"
|
||||
);
|
||||
}
|
||||
_ => syn_error!(lua.params[0], "finaliser parameter must be `self`"),
|
||||
}
|
||||
|
||||
let params = &lua.params;
|
||||
let param = pat_ident(&lua.params[0])?;
|
||||
let body = &lua.body;
|
||||
|
||||
registry.build.push(quote_spanned!(ty.span() =>
|
||||
syn_assert!(param == "self", param, "finaliser parameter must be `self`");
|
||||
|
||||
registry.build.push(quote!(
|
||||
if ::std::mem::needs_drop::<Self>() {
|
||||
// if we have both a lua-side finaliser and a rust drop, then merge the finalisers
|
||||
// by doing the lua part first then drop rust
|
||||
b.declare::<#ffi::UnsafeExternCFn<(*mut Self,), ()>>(#c_name_str);
|
||||
b.declare::<#ffi::ExternCFn<(*mut Self,), ()>>(#c_name_str);
|
||||
b.metatable_raw("gc", #luaify(|self| {
|
||||
raw!(#luaify(#body)); // embed the lua part inside a do block
|
||||
__C::#c_name(self);
|
||||
}));
|
||||
} else {
|
||||
// we only have a lua-side finaliser
|
||||
b.metatable_raw("gc", #luaify(|#(#params),*| #body));
|
||||
b.metatable_raw("gc", #luaify(|self| #body));
|
||||
}
|
||||
));
|
||||
} else {
|
||||
registry.build.push(quote_spanned!(ty.span() =>
|
||||
registry.build.push(quote!(
|
||||
if ::std::mem::needs_drop::<Self>() {
|
||||
// we only have a rust drop
|
||||
b.declare::<#ffi::UnsafeExternCFn<(*mut Self,), ()>>(#c_name_str);
|
||||
b.declare::<#ffi::ExternCFn<(*mut Self,), ()>>(#c_name_str);
|
||||
b.metatable_raw("gc", ::std::format_args!("__C.{}", #c_name_str));
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
registry.shims.push(parse_quote_spanned!(ty.span() =>
|
||||
registry.shims.push(parse_quote!(
|
||||
#[unsafe(export_name = #c_name_str)]
|
||||
unsafe extern "C" fn #shim_name(ptr: *mut Self) {
|
||||
unsafe { ::std::ptr::drop_in_place(ptr) }
|
||||
|
||||
Reference in New Issue
Block a user