Skip to main content

mlua_gen_macros/
lib.rs

1use {
2    attr::Attributes,
3    proc_macro::TokenStream,
4    proc_macro2::TokenStream as TokenStream2,
5    quote::quote,
6    syn::{Data, DeriveInput, parse_macro_input},
7};
8
9mod attr;
10pub(crate) mod builder;
11mod r#enum;
12mod shared;
13pub(crate) mod r#struct;
14
15macro_rules! dbg {
16    ($val:expr $(,)?) => {
17        // Use of `match` here is intentional because it affects the lifetimes
18        // of temporaries - https://stackoverflow.com/a/48732525/1063961
19        match $val {
20            tmp => {
21                #[cfg(feature = "debug")]
22                eprintln!(
23                    "[{}:{}:{}] {} = {}",
24                    std::file!(),
25                    std::line!(),
26                    std::column!(),
27                    std::stringify!($val),
28                    &tmp
29                );
30                tmp
31            },
32        }
33    };
34}
35
36#[proc_macro_attribute]
37pub fn mlua_gen(args: TokenStream, input: TokenStream) -> TokenStream {
38    let input = parse_macro_input!(input as DeriveInput);
39    let name = &input.ident;
40    let generics = &input.generics;
41
42    let mut attributes = Attributes::default();
43    let attr_parser = syn::meta::parser(|meta| attributes.parse(&meta));
44    parse_macro_input!(args with attr_parser);
45
46    let code = match input.data {
47        Data::Struct(ref ds) => {
48            match (|| -> syn::Result<TokenStream2> {
49                let field_get = attributes.get.fields_from_visibility(&ds.fields)?;
50                let field_set = attributes.set.fields_from_visibility(&ds.fields)?;
51
52                let builder = r#struct::builder(
53                    name,
54                    ds,
55                    attributes
56                        .r#impl
57                        .iter()
58                        .filter(|fun| !fun.is_self)
59                        .collect(),
60                    generics,
61                );
62
63                let user_data = r#struct::user_data(
64                    name,
65                    generics,
66                    &ds.fields,
67                    field_get,
68                    field_set,
69                    attributes.custom_fields,
70                    attributes.r#impl,
71                    attributes.custom_impls,
72                );
73
74                Ok(quote!(#builder #user_data))
75            })() {
76                // Ok(e) => dbg!(e),
77                Ok(e) => e,
78                Err(synerr) => return synerr.into_compile_error().into(),
79            }
80        },
81        Data::Enum(ref de) => {
82            let builder = r#enum::builder(
83                name,
84                de,
85                attributes
86                    .r#impl
87                    .iter()
88                    .filter(|fun| !fun.is_self)
89                    .collect(),
90                generics,
91            );
92            let user_data = r#enum::user_data(
93                name,
94                generics,
95                de.variants.iter(),
96                attributes.custom_fields,
97                attributes.custom_impls,
98            );
99            dbg!(quote!(#builder #user_data))
100        },
101        Data::Union(_) => panic!("Must annotate struct or enum"),
102    };
103
104    quote! {
105        #input
106
107        #code
108    }
109    .into()
110}