1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::quote; use syn::{parse_macro_input, Data, DeriveInput, Fields, FieldsNamed, FieldsUnnamed, Ident, Index}; fn builder_for_unnamed(name: TokenStream2, fields: &FieldsUnnamed) -> TokenStream2 { let i = (0..fields.unnamed.len()).map(Index::from); let types = fields.unnamed.iter().map(|f| &f.ty); quote! { ctx.create_function(|_, args: (#(#types,)*)| { Ok(#name (#(args.#i,)*)) }) } } fn builder_for_named(name: TokenStream2, fields: &FieldsNamed) -> TokenStream2 { let names = fields.named.iter().map(|x| &x.ident); let types = fields.named.iter().map(|x| &x.ty); quote! { ctx.create_function(|_, data: rlua::Table<'s>| { Ok(#name { #( #names: data.get::<_, #types>(stringify!(#names))?, )* }) }) } } fn builder_for_fields(name: TokenStream2, fields: &Fields) -> TokenStream2 { match fields { Fields::Unit => quote! { Ok(#name) }, Fields::Unnamed(unnamed) => builder_for_unnamed(name, unnamed), Fields::Named(named) => builder_for_named(name, named), } } fn function_struct_builder(name: Ident, builder: TokenStream2) -> TokenStream2 { quote! { impl<'s> LuaStructBuilder<'s, rlua::Function<'s>> for #name { fn builder(ctx: rlua::Context<'s>) -> rlua::Result<rlua::Function<'s>> { #builder } } } } fn self_struct_builder(name: Ident, builder: TokenStream2) -> TokenStream2 { quote! { impl<'s> LuaStructBuilder<'s, Self> for #name { fn builder(ctx: rlua::Context<'s>) -> rlua::Result<Self> { #builder } } } } #[proc_macro_derive(LuaStructBuilder)] pub fn derive_struct_builder(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = input.ident; let ds = match input.data { Data::Struct(ds) => ds, _ => panic!("Must annotate struct"), }; let code = builder_for_fields(quote! {Self}, &ds.fields); let code = match ds.fields { Fields::Unit => self_struct_builder(name, code), Fields::Unnamed(..) | Fields::Named(..) => function_struct_builder(name, code), }; TokenStream::from(code) } #[proc_macro_derive(LuaEnumBuilder)] pub fn derive_enum_builder(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = input.ident; let de = match input.data { Data::Enum(de) => de, _ => panic!("Must annotate enum"), }; let (names, builders): (Vec<_>, Vec<_>) = de .variants .iter() .map(|v| { let var_name = &v.ident; ( var_name, builder_for_fields(quote! {#name::#var_name}, &v.fields), ) }) .unzip(); let code = quote! { impl<'s> LuaEnumBuilder<'s> for #name { fn builder(ctx: rlua::Context<'s>) -> rlua::Result<rlua::Table<'s>> { let t = ctx.create_table()?; #( t.set(stringify!(#names), #builders?)?; )* Ok(t) } } }; TokenStream::from(code) } #[proc_macro_derive(UserData)] pub fn derive_user_data(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = input.ident; let expanded = quote! { impl UserData for #name {} }; TokenStream::from(expanded) }