rlua_table_derive/
lib.rs

1#![recursion_limit = "1024"]
2extern crate rlua;
3extern crate syn;
4#[macro_use] extern crate quote;
5
6extern crate proc_macro;
7
8use proc_macro::{TokenStream};
9use syn::{VariantData,Ident};
10
11trait FromLuaTable {
12    fn from_table(table: &rlua::Table) -> Self;
13}
14
15#[proc_macro_derive(FromLuaTable)]
16pub fn from_lua_table(input: TokenStream) -> TokenStream {
17    let source = input.to_string();
18    let ast = syn::parse_macro_input(&source).unwrap();
19
20    let idents: Vec<Ident> = match ast.body {
21        syn::Body::Struct(vdata) => {
22            match vdata {
23                VariantData::Struct(fields) => {
24                    let mut idents = Vec::new();
25                    for ref field in fields.iter() {
26                        match &field.ident {
27                            &Some(ref ident) => {
28                                idents.push(ident.clone());
29                            },
30                            &None => panic!("The structure is missing a field identity"),
31                        }
32                    }
33                    idents
34                },
35                VariantData::Tuple(_) | VariantData::Unit => {
36                    panic!("This can only be derived for structs");
37                },
38            }
39        },
40        syn::Body::Enum(_) => panic!("This is only defined for structs"),
41    };
42
43    // contains quoted strings containing the struct fields in the same order as the vector of
44    // idents.
45    let mut keys = Vec::new();
46    for ident in idents.iter() {
47        keys.push(String::from(ident.as_ref()));
48    }
49
50
51    let name = &ast.ident;
52    #[allow(unused)]
53    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
54
55    let tokens = quote! {
56        impl #impl_generics FromLuaTable for #name #ty_generics #where_clause {
57            #[allow(unused)]
58            fn from_lua_table(table: &rlua::Table) -> Self {
59                #[allow(unused_mut)]
60                let mut ret = #name::default();
61
62                #(
63                    if let Ok(val) = table.get(#keys) {
64                        ret.#idents = val;
65                    }
66                )*
67                ret
68            }
69        }
70    };
71    tokens.parse().unwrap()
72}
73
74#[cfg(test)]
75mod tests {
76    /*
77    #[test]
78    fn it_works() {
79        assert_eq!(2 + 2, 4);
80    }
81    */
82}
83
84