reflection_derive/
lib.rs

1#![recursion_limit="128"]
2
3extern crate proc_macro;
4extern crate syn;
5
6extern crate serde_derive_internals;
7use serde_derive_internals::attr::get_serde_meta_items;
8
9use syn::Meta::{NameValue,Word};
10use syn::NestedMeta::Meta;
11
12#[macro_use]
13extern crate quote;
14
15use proc_macro::TokenStream;
16use syn::{ DeriveInput, Data, Fields, Generics, GenericParam };
17use quote::Tokens;
18
19#[proc_macro_derive( Reflection )]
20pub fn derive_reflection( input: TokenStream) -> TokenStream {
21    let input: DeriveInput = syn::parse( input ).unwrap();
22    let name = input.ident;
23    let generics = add_trait_bounds( input.generics );
24    let ( impl_generics, ty_generics, where_clause ) = generics.split_for_impl();
25    let members = aggregate( &input.data );
26    let schema = generate_schema( &input.data );
27    let ty = generate_ty( &input.data );
28
29    let expanded = quote! {
30        impl #impl_generics ::reflection::Reflection for #name #ty_generics #where_clause {
31            fn ty() -> ::reflection::Type { #ty }
32            fn name() -> ::reflection::Name { Some( String::from( stringify!( #name )))}
33
34            fn schema( id: ::reflection::Id ) -> ::reflection::Schema {
35                let mut tree = {#schema};
36                match &mut tree.root_mut().data {
37                    ::reflection::Member::Field( ref mut field ) => {
38                        field.id = id;
39                        field.tyname = Self::name();
40                        field.expander = Some( <#name #ty_generics as Reflection>::members );
41                    },
42                    ::reflection::Member::Variant( ref mut variant ) => {
43                        variant.id = id;
44                    },
45                }
46                tree
47            }
48
49            fn members() -> ::reflection::Schemas { #members }
50        }
51    };
52
53    expanded.into()
54}
55
56fn add_trait_bounds( mut generics: Generics ) -> Generics {
57    for param in &mut generics.params {
58        if let GenericParam::Type( ref mut type_param ) = *param {
59            let bound = syn::parse_str( "::reflection::Reflection" ).unwrap();
60            type_param.bounds.push( bound );
61        }
62    }
63    generics
64}
65
66fn is_skipped( attrs: &Vec<syn::Attribute> ) -> bool {
67    for meta_items in attrs.iter().filter_map( get_serde_meta_items ) {
68        for meta_item in meta_items {
69            match meta_item {
70                // Parse `#[serde(skip_serializing)]`
71                Meta( Word( word )) if word == "skip_serializing" => {
72                    return true
73                }
74                _ => continue
75            }
76        }
77    }
78    false
79}
80
81fn serde_rename( field: &syn::Field ) -> Option<String> {
82    for meta_items in field.attrs.iter().filter_map( get_serde_meta_items ) {
83        for meta_item in meta_items {
84            match meta_item {
85                // Parse `#[serde(rename = "foo")]`
86                Meta( NameValue( ref m )) if m.ident == "rename" => {
87                    if let syn::Lit::Str( ref lit ) = *&m.lit {
88                        return Some( lit.value() )
89                    }
90                }
91                _ => continue
92            }
93        }
94    }
95    None
96}
97
98fn generate_ty( data: &Data ) -> Tokens {
99    match *data {
100        Data::Struct(_) => {
101            quote!( ::reflection::Type::Struct )
102        }
103        Data::Enum(_) => {
104            quote!( ::reflection::Type::Enum )
105        } 
106        Data::Union(_) => unimplemented!()
107    }
108}
109
110fn generate_schema( data: &Data ) -> Tokens {
111    match *data {
112        Data::Struct(_) => {
113            quote!( ::reflection::field( "_", ::reflection::Type::Struct, None, None ))
114        }
115        Data::Enum(_) => {
116            quote!( ::reflection::field( "_", ::reflection::Type::Enum, None, None ))
117        } 
118        Data::Union(_) => unimplemented!()
119    }
120}
121
122fn aggregate( data: &Data ) -> Tokens {
123    match *data {
124        Data::Struct( ref data ) => {
125            match data.fields {
126                Fields::Named( ref fields ) => {
127                    let fnames = fields.named.iter().filter( |f| !is_skipped( &f.attrs )).map( |f|
128                        match serde_rename(f) {
129                            Some( name ) => name,
130                            None => f.ident.unwrap().to_string()
131                        }
132                    );
133                    let ftypes1 = fields.named.iter().map( |f| f.ty.clone() );
134                    let ftypes2 = fields.named.iter().map( |f| f.ty.clone() );
135                    let ftypes3 = fields.named.iter().map( |f| f.ty.clone() );
136                    quote! {
137                        #(
138                            -( ::reflection::field(
139                                    #fnames,
140                                    <#ftypes1 as ::reflection::Reflection>::ty(),
141                                    <#ftypes2 as ::reflection::Reflection>::name(),
142                                    Some( <#ftypes3 as ::reflection::Reflection>::members )))
143                        )*
144                    }
145                }
146                Fields::Unnamed( ref fields ) => {
147                    let mut i = 0;
148                    let indices = fields.unnamed.iter().filter( |f| !is_skipped( &f.attrs )).map( |f|
149                        match serde_rename(f) {
150                            Some( name ) => name,
151                            None => { i += 1; return (i-1).to_string() }
152                        }
153                    );
154                    let ftypes1 = fields.unnamed.iter().map( |f| f.ty.clone() );
155                    let ftypes2 = fields.unnamed.iter().map( |f| f.ty.clone() );
156                    let ftypes3 = fields.unnamed.iter().map( |f| f.ty.clone() );
157                    quote! {
158                        #(
159                            -( ::reflection::field(
160                                    #indices,
161                                    <#ftypes1 as ::reflection::Reflection>::ty(),
162                                    <#ftypes2 as ::reflection::Reflection>::name(),
163                                    Some( <#ftypes3 as ::reflection::Reflection>::members )))
164                        )*
165                    }
166                }
167                Fields::Unit => {
168                    quote!( ::reflection::Schemas::new() )
169                }
170            }
171        }
172        Data::Enum( ref data ) => {
173            let vnames = data.variants.iter().map( |v| v.ident );
174
175            let fnames = data.variants.iter().map( |v| {
176                let mut i = 0;
177                v.fields.iter().filter( |f| !is_skipped( &f.attrs )).map( move |f| {
178                    match serde_rename(f) {
179                        Some( name ) => name,
180                        None => {
181                            if let Some( ident ) = f.ident {
182                                ident.to_string()
183                            } else {
184                                i += 1;
185                                (i-1).to_string()
186                            }
187                        }
188                    }
189                })
190            });
191
192            let ftypes1 = data.variants.iter().map( |v|
193                v.fields.iter().map( |fields| fields.ty.clone() )
194            );
195            let ftypes2 = data.variants.iter().map( |v|
196                v.fields.iter().map( |fields| fields.ty.clone() )
197            );
198            let ftypes3 = data.variants.iter().map( |v|
199                v.fields.iter().map( |fields| fields.ty.clone() )
200            );
201
202            quote! {
203                #(
204                    -( ::reflection::variant( stringify!( #vnames ))
205                        /(
206                            #(
207                                -( ::reflection::field(
208                                        #fnames,
209                                        <#ftypes1 as ::reflection::Reflection>::ty(),
210                                        <#ftypes2 as ::reflection::Reflection>::name(),
211                                        Some( <#ftypes3 as ::reflection::Reflection>::members )))
212                            )*
213                        )
214                    )
215                )*
216            }
217        } 
218        Data::Union(_) => unimplemented!()
219    }
220}