Automatically generate drop for #[metatype]
This commit is contained in:
parent
8f6fc64f7a
commit
f9676a1436
@ -7,6 +7,7 @@ edition = "2024"
|
|||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
darling = "0.20.11"
|
||||||
proc-macro2 = "1.0.95"
|
proc-macro2 = "1.0.95"
|
||||||
quote = "1.0.40"
|
quote = "1.0.40"
|
||||||
syn = { version = "2.0.103", features = ["full", "visit-mut"] }
|
syn = { version = "2.0.103", features = ["full", "visit-mut"] }
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
use crate::utils::{ffi_crate, syn_assert, syn_error};
|
use crate::utils::{ffi_crate, syn_assert, syn_error};
|
||||||
|
use darling::FromMeta;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use syn::{spanned::*, *};
|
use syn::{spanned::*, *};
|
||||||
|
|
||||||
pub fn transform(mut item: Item) -> Result<TokenStream> {
|
#[derive(Debug, FromMeta)]
|
||||||
|
pub struct Args {
|
||||||
|
module: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform(args: Args, mut item: Item) -> Result<TokenStream> {
|
||||||
let (name, impl_type, impl_cdef) = match item {
|
let (name, impl_type, impl_cdef) = match item {
|
||||||
Item::Struct(ref mut str) => (
|
Item::Struct(ref mut str) => (
|
||||||
str.ident.clone(),
|
str.ident.clone(),
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use darling::{FromMeta, ast::NestedMeta};
|
||||||
use proc_macro::TokenStream as TokenStream1;
|
use proc_macro::TokenStream as TokenStream1;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use syn::parse_macro_input;
|
use syn::parse_macro_input;
|
||||||
@ -8,7 +9,9 @@ mod utils;
|
|||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn cdef(args: TokenStream1, input: TokenStream1) -> TokenStream1 {
|
pub fn cdef(args: TokenStream1, input: TokenStream1) -> TokenStream1 {
|
||||||
cdef::transform(parse_macro_input!(input))
|
NestedMeta::parse_meta_list(args.into())
|
||||||
|
.and_then(|meta| cdef::Args::from_list(&meta).map_err(Into::into))
|
||||||
|
.and_then(|args| cdef::transform(args, syn::parse(input)?))
|
||||||
.unwrap_or_else(|err| err.into_compile_error().into_token_stream())
|
.unwrap_or_else(|err| err.into_compile_error().into_token_stream())
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
@ -26,25 +26,36 @@ pub fn transform(mut imp: ItemImpl) -> Result<TokenStream> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generate_impls(imp: &mut ItemImpl) -> Result<TokenStream> {
|
fn generate_impls(imp: &mut ItemImpl) -> Result<TokenStream> {
|
||||||
|
let ty = imp.self_ty.clone();
|
||||||
|
let ty_name = ty_name(&ty)?;
|
||||||
|
|
||||||
let ffi = ffi_crate();
|
let ffi = ffi_crate();
|
||||||
let ffi_funcs = get_ffi_functions(imp)?;
|
let ffi_funcs = get_ffi_functions(imp)?;
|
||||||
let ffi_wrappers: Vec<_> = ffi_funcs
|
let ffi_wrappers: Vec<_> = ffi_funcs
|
||||||
.iter()
|
.iter()
|
||||||
.map(generate_ffi_wrapper)
|
.map(generate_ffi_wrapper)
|
||||||
.collect::<Result<_>>()?;
|
.collect::<Result<_>>()?;
|
||||||
|
|
||||||
let ffi_register: Vec<_> = ffi_funcs
|
let ffi_register: Vec<_> = ffi_funcs
|
||||||
.iter()
|
.iter()
|
||||||
.map(generate_ffi_register)
|
.map(generate_ffi_register)
|
||||||
.collect::<Result<_>>()?;
|
.collect::<Result<_>>()?;
|
||||||
|
|
||||||
|
let ffi_drop_fn = format_ident!("__ffi_drop");
|
||||||
|
let ffi_drop_name = format!("{ty_name}_drop");
|
||||||
|
|
||||||
|
let ffi_exports = {
|
||||||
|
let mut names = vec![&ffi_drop_fn];
|
||||||
|
names.extend(ffi_funcs.iter().map(|f| &f.rust_name));
|
||||||
|
generate_ffi_exports(&ty, names.into_iter())?
|
||||||
|
};
|
||||||
|
|
||||||
let lua_funcs = get_lua_functions(imp)?;
|
let lua_funcs = get_lua_functions(imp)?;
|
||||||
let lua_register: Vec<_> = lua_funcs
|
let lua_register: Vec<_> = lua_funcs
|
||||||
.iter()
|
.iter()
|
||||||
.map(generate_lua_register)
|
.map(generate_lua_register)
|
||||||
.collect::<Result<_>>()?;
|
.collect::<Result<_>>()?;
|
||||||
|
|
||||||
let ty = &*imp.self_ty;
|
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
unsafe impl #ffi::Metatype for #ty {
|
unsafe impl #ffi::Metatype for #ty {
|
||||||
type Target = Self;
|
type Target = Self;
|
||||||
@ -52,10 +63,22 @@ fn generate_impls(imp: &mut ItemImpl) -> Result<TokenStream> {
|
|||||||
fn build(b: &mut #ffi::MetatypeBuilder) {
|
fn build(b: &mut #ffi::MetatypeBuilder) {
|
||||||
#(#ffi_register)*
|
#(#ffi_register)*
|
||||||
#(#lua_register)*
|
#(#lua_register)*
|
||||||
|
|
||||||
|
b.declare::<unsafe extern "C" fn(*mut Self)>(#ffi_drop_name);
|
||||||
|
b.metatable_raw("gc", ::std::format_args!("C.{}", #ffi_drop_name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl #ty { #(#ffi_wrappers)* }
|
impl #ty {
|
||||||
|
#(#ffi_wrappers)*
|
||||||
|
|
||||||
|
#[unsafe(export_name = #ffi_drop_name)]
|
||||||
|
unsafe extern "C" fn #ffi_drop_fn(&mut self) {
|
||||||
|
unsafe { ::std::ptr::drop_in_place(self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ffi_exports
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,6 +236,19 @@ fn generate_ffi_register(func: &FfiFunction) -> Result<TokenStream> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_ffi_exports<'a>(
|
||||||
|
ty: &Type,
|
||||||
|
names: impl Iterator<Item = &'a Ident>,
|
||||||
|
) -> Result<TokenStream> {
|
||||||
|
Ok(quote! {
|
||||||
|
// hack to prevent ffi functions from being dead code-eliminated
|
||||||
|
#[used]
|
||||||
|
static __FFI_EXPORTS: &[fn()] = unsafe {
|
||||||
|
&[#(::std::mem::transmute(#ty::#names as *const ())),*]
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
struct LuaFunction {
|
struct LuaFunction {
|
||||||
name: String,
|
name: String,
|
||||||
params: Vec<PatType>,
|
params: Vec<PatType>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user