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 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 }
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 }
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 }
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}