scrapmetal_derive/
lib.rs

1#![recursion_limit = "1000"]
2
3extern crate proc_macro;
4extern crate syn;
5#[macro_use]
6extern crate quote;
7
8use proc_macro::TokenStream;
9use quote::Tokens;
10
11#[proc_macro_derive(Term)]
12pub fn derive_into_heap(input: TokenStream) -> TokenStream {
13    let source = input.to_string();
14    let ast = syn::parse_derive_input(&source).unwrap();
15    let expanded = impl_term(&ast);
16
17    // Uncomment to debug the generated code...
18    // println!("\n\n{:?}", expanded);
19
20    expanded.parse().unwrap()
21}
22
23fn impl_term(ast: &syn::DeriveInput) -> Tokens {
24    match ast.body {
25        syn::Body::Struct(ref data) => impl_term_for_struct(ast, data),
26        syn::Body::Enum(ref variants) => impl_term_for_enum(ast, variants),
27    }
28}
29
30fn impl_term_for_struct(ast: &syn::DeriveInput, data: &syn::VariantData) -> Tokens {
31    match *data {
32        syn::VariantData::Struct(ref fields) => impl_term_for_struct_struct(ast, fields),
33        syn::VariantData::Tuple(ref fields) => impl_term_for_tuple_struct(ast, fields),
34        syn::VariantData::Unit => impl_term_for_unit_struct(ast),
35    }
36}
37
38fn impl_term_for_struct_struct(ast: &syn::DeriveInput, fields: &[syn::Field]) -> Tokens {
39    let name = &ast.ident;
40    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
41
42    let transforms: Vec<_> = fields.iter()
43        .map(|f| {
44            quote! {
45                #f.ident : f.transform(self.#f.ident) ,
46            }
47        })
48        .collect();
49
50    let queries: Vec<_> = fields.iter()
51        .map(|f| {
52            quote! {
53                let r = q.query(&self.#f.ident);
54                each(q, r);
55            }
56        })
57        .collect();
58
59    let mutations: Vec<_> = fields.iter()
60        .map(|f| {
61            quote! {
62                let r = m.mutate(&mut self.#f.indent);
63                each(m, r);
64            }
65        })
66        .collect();
67
68    quote! {
69        impl #impl_generics ::scrapmetal::Term for #name #ty_generics
70            #where_clause
71        {
72            #[inline]
73            #[allow(unused_variables)]
74            #[allow(unused_mut)]
75            fn map_one_transform<F>(self, f: &mut F) -> Self
76            where
77                F: ::scrapmetal::GenericTransform,
78            {
79                Self {
80                    #( #transforms )*
81                }
82            }
83
84            #[inline]
85            #[allow(unused_variables)]
86            #[allow(unused_mut)]
87            fn map_one_query<Q, R, F>(&self, q: &mut Q, mut each: F)
88            where
89                Q: ::scrapmetal::GenericQuery<R>,
90                F: FnMut(&mut Q, R),
91            {
92                #( #queries )*
93            }
94
95            #[inline]
96            #[allow(unused_variables)]
97            #[allow(unused_mut)]
98            fn map_one_mutation<M, R, F>(&mut self, mutation: &mut M, mut each: F)
99            where
100                M: ::scrapmetal::GenericMutate<R>,
101                F: FnMut(&mut M, R),
102            {
103                #( #mutations )*
104            }
105        }
106    }
107}
108
109fn impl_term_for_tuple_struct(ast: &syn::DeriveInput, fields: &[syn::Field]) -> Tokens {
110    let name = &ast.ident;
111    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
112
113    let fields: Vec<_> = (0..fields.len()).map(syn::Ident::new).collect();
114
115    let transforms: Vec<_> = fields.iter()
116        .map(|i| {
117            quote! {
118                f.transform(self.#i) ,
119            }
120        })
121        .collect();
122
123    let queries: Vec<_> = fields.iter()
124        .map(|i| {
125            quote! {
126                let r = q.query(&self.#i);
127                each(q, r);
128            }
129        })
130        .collect();
131
132    let mutations: Vec<_> = fields.iter()
133        .map(|i| {
134            quote! {
135                let r = m.mutate(&mut self.#i);
136                each(m, r);
137            }
138        })
139        .collect();
140
141    quote! {
142        impl #impl_generics ::scrapmetal::Term for #name #ty_generics
143            #where_clause
144        {
145            #[inline]
146            #[allow(unused_variables)]
147            #[allow(unused_mut)]
148            fn map_one_transform<F>(self, f: &mut F) -> Self
149            where
150                F: ::scrapmetal::GenericTransform,
151            {
152                #name ( #( #transforms )* )
153            }
154
155            #[inline]
156            #[allow(unused_variables)]
157            #[allow(unused_mut)]
158            fn map_one_query<Q, R, F>(&self, q: &mut Q, mut each: F)
159            where
160                Q: ::scrapmetal::GenericQuery<R>,
161                F: FnMut(&mut Q, R),
162            {
163                #( #queries )*
164            }
165
166            #[inline]
167            #[allow(unused_variables)]
168            #[allow(unused_mut)]
169            fn map_one_mutation<M, R, F>(&mut self, m: &mut M, mut each: F)
170            where
171                M: ::scrapmetal::GenericMutate<R>,
172                F: FnMut(&mut M, R),
173            {
174                #( #mutations )*
175            }
176        }
177    }
178}
179
180fn impl_term_for_unit_struct(ast: &syn::DeriveInput) -> Tokens {
181    let name = &ast.ident;
182    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
183
184    quote! {
185        impl #impl_generics ::scrapmetal::Term for #name #ty_generics
186            #where_clause
187        {
188            #[inline(always)]
189            fn map_one_transform<F>(self, _: &mut F) -> Self
190            where
191                F: ::scrapmetal::GenericTransform,
192            {
193                self
194            }
195
196            #[inline(always)]
197            fn map_one_query<Q, R, F>(&self, _: &mut Q, _: F)
198            where
199                Q: ::scrapmetal::GenericQuery<R>,
200                F: FnMut(&mut Q, R),
201            {}
202
203            #[inline(always)]
204            fn map_one_mutation<M, R, F>(&mut self, _: &mut M, _: F)
205            where
206                M: ::scrapmetal::GenericMutate<R>,
207                F: FnMut(&mut M, R),
208            {}
209        }
210    }
211}
212
213fn impl_term_for_enum(ast: &syn::DeriveInput, variants: &[syn::Variant]) -> Tokens {
214    let name = &ast.ident;
215    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
216
217    let transforms: Vec<_> = variants.iter()
218        .map(|v| {
219            let variant_ident = &v.ident;
220            match v.data {
221                syn::VariantData::Struct(ref fields) => {
222                    let field_names: Vec<_> = fields.iter()
223                        .map(|f| {
224                            let ident = &f.ident;
225                            quote! {
226                                #ident ,
227                            }
228                        })
229                        .collect();
230
231                    let field_transforms: Vec<_> = fields.iter()
232                        .map(|f| {
233                            let ident = &f.ident;
234                            quote! {
235                                #ident : f.transform( #ident ) ,
236                            }
237                        })
238                        .collect();
239
240                    quote! {
241                        #name :: #variant_ident { #( #field_names )* } => {
242                            #name :: #variant_ident { #( #field_transforms )* }
243                        }
244                    }
245                }
246                syn::VariantData::Tuple(ref fields) => {
247                    let tuple_names: Vec<_> = (0..fields.len())
248                        .map(|i| {
249                            let c = ('a' as u8 + i as u8) as char;
250                            let mut s = String::with_capacity(1);
251                            s.push(c);
252                            syn::Ident::new(s)
253                        })
254                        .collect();
255
256                    let tuple_patterns: Vec<_> = tuple_names.iter()
257                        .map(|p| {
258                            quote! {
259                                #p ,
260                            }
261                        })
262                        .collect();
263
264                    let tuple_transforms: Vec<_> = tuple_names.iter()
265                        .map(|p| {
266                            quote! {
267                                f.transform( #p ) ,
268                            }
269                        })
270                        .collect();
271
272                    quote! {
273                        #name :: #variant_ident ( #( #tuple_patterns )* ) => {
274                            #name :: #variant_ident ( #( #tuple_transforms )* )
275                        }
276                    }
277                }
278                syn::VariantData::Unit => {
279                    quote! {
280                        // Nothing to do here.
281                    }
282                }
283            }
284        })
285        .collect();
286
287    let queries: Vec<_> = variants.iter()
288        .map(|v| {
289            let variant_ident = &v.ident;
290            match v.data {
291                syn::VariantData::Struct(ref fields) => {
292                    let field_names: Vec<_> = fields.iter()
293                        .map(|f| {
294                            let ident = &f.ident;
295                            quote! {
296                                ref #ident ,
297                            }
298                        })
299                        .collect();
300
301                    let field_queries: Vec<_> = fields.iter()
302                        .map(|f| {
303                            let ident = &f.ident;
304                            quote! {
305                                let r = q.query( #ident );
306                                each(q, r);
307                            }
308                        })
309                        .collect();
310
311                    quote! {
312                        #name :: #variant_ident { #( #field_names )* } => {
313                            #( #field_queries )*
314                        }
315                    }
316                }
317                syn::VariantData::Tuple(ref fields) => {
318                    let tuple_names: Vec<_> = (0..fields.len())
319                        .map(|i| {
320                            let c = ('a' as u8 + i as u8) as char;
321                            let mut s = String::with_capacity(1);
322                            s.push(c);
323                            syn::Ident::new(s)
324                        })
325                        .collect();
326
327                    let tuple_patterns: Vec<_> = tuple_names.iter()
328                        .map(|p| {
329                            quote! {
330                                ref #p ,
331                            }
332                        })
333                        .collect();
334
335                    let tuple_queries: Vec<_> = tuple_names.iter()
336                        .map(|p| {
337                            quote! {
338                                let r = q.query( #p );
339                                each(q, r);
340                            }
341                        })
342                        .collect();
343
344                    quote! {
345                        #name :: #variant_ident ( #( #tuple_patterns )* ) => {
346                            #( #tuple_queries )*
347                        }
348                    }
349                }
350                syn::VariantData::Unit => {
351                    quote! {
352                        // Nothing to do here.
353                    }
354                }
355            }
356        })
357        .collect();
358
359    let mutations: Vec<_> = variants.iter()
360        .map(|v| {
361            let variant_ident = &v.ident;
362            match v.data {
363                syn::VariantData::Struct(ref fields) => {
364                    let field_names: Vec<_> = fields.iter()
365                        .map(|f| {
366                            let ident = &f.ident;
367                            quote! {
368                                ref mut #ident ,
369                            }
370                        })
371                        .collect();
372
373                    let field_mutations: Vec<_> = fields.iter()
374                        .map(|f| {
375                            let ident = &f.ident;
376                            quote! {
377                                let r = m.mutate( #ident );
378                                each(m, r);
379                            }
380                        })
381                        .collect();
382
383                    quote! {
384                        #name :: #variant_ident { #( #field_names )* } => {
385                            #( #field_mutations )*
386                        }
387                    }
388                }
389                syn::VariantData::Tuple(ref fields) => {
390                    let tuple_names: Vec<_> = (0..fields.len())
391                        .map(|i| {
392                            let c = ('a' as u8 + i as u8) as char;
393                            let mut s = String::with_capacity(1);
394                            s.push(c);
395                            syn::Ident::new(s)
396                        })
397                        .collect();
398
399                    let tuple_patterns: Vec<_> = tuple_names.iter()
400                        .map(|p| {
401                            quote! {
402                                ref mut #p ,
403                            }
404                        })
405                        .collect();
406
407                    let tuple_mutations: Vec<_> = tuple_names.iter()
408                        .map(|p| {
409                            quote! {
410                                let r = m.mutate( #p );
411                                each(m, r);
412                            }
413                        })
414                        .collect();
415
416                    quote! {
417                        #name :: #variant_ident ( #( #tuple_patterns )* ) => {
418                            #( #tuple_mutations )*
419                        }
420                    }
421                }
422                syn::VariantData::Unit => {
423                    quote! {
424                        // Nothing to do here.
425                    }
426                }
427            }
428        })
429        .collect();
430
431    quote! {
432        impl #impl_generics ::scrapmetal::Term for #name #ty_generics
433            #where_clause
434        {
435            #[inline]
436            #[allow(unused_variables)]
437            #[allow(unused_mut)]
438            fn map_one_transform<F>(self, f: &mut F) -> Self
439            where
440                F: ::scrapmetal::GenericTransform,
441            {
442                match self {
443                    #( #transforms )*
444                }
445            }
446
447            #[inline]
448            #[allow(unused_variables)]
449            #[allow(unused_mut)]
450            fn map_one_query<Q, R, F>(&self, q: &mut Q, mut each: F)
451            where
452                Q: ::scrapmetal::GenericQuery<R>,
453                F: FnMut(&mut Q, R),
454            {
455                match *self {
456                    #( #queries )*
457                }
458            }
459
460            #[inline]
461            #[allow(unused_variables)]
462            #[allow(unused_mut)]
463            fn map_one_mutation<M, R, F>(&mut self, m: &mut M, mut each: F)
464            where
465                M: ::scrapmetal::GenericMutate<R>,
466                F: FnMut(&mut M, R),
467            {
468                match *self {
469                    #( #mutations )*
470                }
471            }
472        }
473    }
474}