1use proc_macro::TokenStream;
2use proc_macro2::Span;
3use quote::quote;
4use syn;
5
6const DOC_ATTR: &str = "inherit_doc";
7const INNER_DOC_ATTR: &str = "inherit_docs";
8
9#[proc_macro_derive(CompileConst, attributes(inherit_doc, inherit_docs))]
12pub fn const_gen_derive(input: TokenStream) -> TokenStream
13{
14 impl_macro(&syn::parse(input).unwrap())
15}
16
17fn impl_macro(ast: &syn::DeriveInput) -> TokenStream
18{
19 let name = &ast.ident;
20 let generics = &ast.generics;
21 let val_impl: proc_macro2::TokenStream = match &ast.data
22 {
23 syn::Data::Struct(data) => struct_val_handler(name, &data.fields),
24 syn::Data::Enum(data) =>
25 {
26 let arms: Vec<proc_macro2::TokenStream> = data.variants
27 .iter()
28 .map(|v| enum_val_handler(name, &v.ident, &v.fields))
29 .collect();
30 quote!
31 {
32 format!("{}", match self
33 {
34 #( #arms, )*
35 })
36 }
37 }
38 syn::Data::Union(data) =>
39 {
40 let vis = get_field_visibilities(&data.fields.named).into_iter().next().unwrap();
41 let ident = get_field_idents(&data.fields.named).into_iter().next().unwrap();
42 quote!
43 {
44 format!
45 (
46 "{} {} {{ {}: {}}}",
47 stringify!(#vis),
48 stringify!(#name),
49 stringify!(#ident),
50 self.#ident.const_val()
51 )
52 }
53 }
54 };
55 let (doc_attr, inner_doc_attr) = get_docs(&ast.attrs);
56 let def_impl: proc_macro2::TokenStream = match &ast.data
57 {
58 syn::Data::Struct(data) => struct_def_handler(name, generics, &data.fields, inner_doc_attr),
59 syn::Data::Enum(data) => enum_def_handler(name, generics, data.variants.iter().collect(), inner_doc_attr),
60 syn::Data::Union(data) =>
61 {
62 let docs = get_field_docs(&data.fields.named, inner_doc_attr);
63 let vis = get_field_visibilities(&data.fields.named);
64 let idents = get_field_idents(&data.fields.named);
65 let types = get_field_types(&data.fields.named);
66 quote!
67 {
68 let mut f = String::new();
69 #( f.push_str(&format!("{} {} {}: {}, ", stringify!(#docs), stringify!(#vis), stringify!(#idents), <#types>::const_type())); )*
70 format!
71 (
72 "union {}{}{{ {}}}",
73 stringify!(#name),
74 stringify!(#generics),
75 f
76 )
77 }
78 }
79 };
80 let doc_attr = doc_attr.map_or(String::new(), |attr| quote!(#attr).to_string());
81 let gen = quote!
82 {
83 impl const_gen::CompileConst for #name #generics
84 {
85 fn const_type() -> String
86 {
87 String::from(stringify!(#name))
88 }
89
90 fn const_val(&self) -> String
91 {
92 #val_impl
93 }
94
95 fn const_definition(attrs: &str, vis: &str) -> String
96 {
97 let mut definition = String::from(attrs);
98 definition += #doc_attr;
99 definition += " ";
100 definition += vis;
101 definition += " ";
102 definition += &{#def_impl};
103 definition
104 }
105 }
106 };
107 gen.into()
108}
109
110fn struct_def_handler(name: &syn::Ident, generics: &syn::Generics, fields: &syn::Fields, inner_doc_attr: bool) -> proc_macro2::TokenStream
112{
113 match fields
114 {
115 syn::Fields::Named(f) =>
116 {
117 let vis = get_field_visibilities(&f.named);
118 let idents = get_field_idents(&f.named);
119 let types = get_field_types(&f.named);
120 let docs = get_field_docs(&f.named, inner_doc_attr);
121 quote!
122 {
123 let mut f = String::new();
124 #( f.push_str(&format!("{} {} {}: {}, ", stringify!(#docs), stringify!(#vis), stringify!(#idents), <#types>::const_type())); )*
125 format!
126 (
127 "struct {}{}{{ {}}}",
128 stringify!(#name),
129 stringify!(#generics),
130 f
131 )
132 }
133 },
134 syn::Fields::Unnamed(f) =>
135 {
136 let types = get_field_types(&f.unnamed);
137 quote!
138 {
139 let mut f = String::new();
140 #( f.push_str(&format!("{},", <#types>::const_type())); )*
141 format!
142 (
143 "struct {}{}({});",
144 stringify!(#name),
145 stringify!(#generics),
146 f
147 )
148 }
149 },
150 syn::Fields::Unit => quote!(format!("struct {}{};", stringify!(#name), stringify!(#generics)))
151 }
152}
153
154fn struct_val_handler(name: &syn::Ident, fields: &syn::Fields) -> proc_macro2::TokenStream
156{
157 match fields
158 {
159 syn::Fields::Named(f) =>
160 {
161 let idents = get_field_idents(&f.named);
162 quote!
163 {
164 let mut f = String::new();
165 #( f.push_str(&format!("{}: {}, ", stringify!(#idents), self.#idents.const_val())); )*
166 format!
167 (
168 "{} {{ {}}}",
169 stringify!(#name),
170 f
171 )
172 }
173 },
174 syn::Fields::Unnamed(f) =>
175 {
176 let mut counter = 0;
177 let vals: Vec<_> = f.unnamed.iter()
178 .map(|_|{let next = counter; counter += 1; next})
179 .map(syn::Index::from).collect();
180 quote!
181 {
182 let mut f = String::new();
183 #( f.push_str(&format!("{},", self.#vals.const_val())); )*
184 format!
185 (
186 "{}({})",
187 stringify!(#name),
188 f
189 )
190 }
191 },
192 syn::Fields::Unit => quote!(stringify!(#name))
193 }
194}
195
196fn enum_val_handler(name: &syn::Ident, var_name: &syn::Ident, fields: &syn::Fields) -> proc_macro2::TokenStream
198{
199 let constructor = match fields
200 {
201 syn::Fields::Named(f) =>
202 {
203 let idents = get_field_idents(&f.named);
204 quote!
205 {{
206 let mut f = String::new();
207 #( f.push_str(&format!("{}:{},", stringify!(#idents), #idents.const_val())); )*
208 format!
209 (
210 "{}::{}{{{}}}",
211 stringify!(#name),
212 stringify!(#var_name),
213 f
214 )
215 }}
216 },
217 syn::Fields::Unnamed(f) =>
218 {
219 let mut counter = 0;
220 let idents: Vec<syn::Ident> = f.unnamed.iter()
221 .map(|_|
222 {
223 let new_ident = syn::Ident::new(&format!("idnt{}", counter), Span::call_site());
224 counter += 1;
225 new_ident
226 })
227 .collect();
228 quote!
229 {{
230 let mut f = String::new();
231 #( f.push_str(&format!("{},", #idents.const_val())); )*
232 format!
233 (
234 "{}::{}({})",
235 stringify!(#name),
236 stringify!(#var_name),
237 f
238 )
239 }}
240 },
241 syn::Fields::Unit => quote!(format!("{}::{}", stringify!(#name), stringify!(#var_name)))
242 };
243 match fields
244 {
245 syn::Fields::Named(f) =>
246 {
247 let new_idents = get_field_idents(&f.named);
248 quote!(Self::#var_name {#(#new_idents, )*} => #constructor)
249 },
250 syn::Fields::Unnamed(f) =>
251 {
252 let mut counter = 0;
253 let new_idents: Vec<syn::Ident> = f.unnamed.iter()
254 .map(|_|
255 {
256 let new_ident = syn::Ident::new(&format!("idnt{}", counter), Span::call_site());
257 counter += 1;
258 new_ident
259 })
260 .collect();
261 quote!(Self::#var_name (#(#new_idents, )*) => #constructor)
262 }
263 syn::Fields::Unit => quote!(Self::#var_name => #constructor)
264 }
265}
266
267fn enum_def_handler(name: &syn::Ident, generics: &syn::Generics, variants: Vec<&syn::Variant>, inner_doc_attr: bool) -> proc_macro2::TokenStream
269{
270 let arms: Vec<proc_macro2::TokenStream> = variants.into_iter()
271 .map(|v| enum_variant_def_handler(&v.attrs, &v.ident, &v.fields, inner_doc_attr))
272 .collect();
273 quote!
274 {
275 format!("enum {}{}{{ {} }}", stringify!(#name), stringify!(#generics), #(#arms+)&* "")
276 }
277}
278
279fn enum_variant_def_handler(attributes: &[syn::Attribute], var_name: &syn::Ident, fields: &syn::Fields, inner_doc_attr: bool) -> proc_macro2::TokenStream
281{
282 let doc_attr = get_inner_docs(attributes, inner_doc_attr);
283 match fields
284 {
285 syn::Fields::Named(f) =>
286 {
287 let idents = get_field_idents(&f.named);
288 let types = get_field_types(&f.named);
289 quote!
290 {{
291 let mut f = String::new();
292 #( f.push_str(&format!("{}:{},", stringify!(#idents), <#types>::const_type())); )*
293 format!
294 (
295 "{} {}{{{}}},",
296 stringify!(#doc_attr),
297 stringify!(#var_name),
298 f
299 )
300 }}
301 },
302 syn::Fields::Unnamed(f) =>
303 {
304 let types = get_field_types(&f.unnamed);
305 quote!
306 {{
307 let mut f = String::new();
308 #( f.push_str(&format!("{},", <#types>::const_type())); )*
309 format!
310 (
311 "{} {}({}),",
312 stringify!(#doc_attr),
313 stringify!(#var_name),
314 f
315 )
316 }}
317 },
318 syn::Fields::Unit => quote!(format!("{} {},", stringify!(#doc_attr), stringify!(#var_name)))
319 }
320}
321
322fn get_field_visibilities(fields: &syn::punctuated::Punctuated<syn::Field, syn::token::Comma>) -> Vec<&syn::Visibility>
324{
325 fields.iter().map(|field|&field.vis).collect()
326}
327
328fn get_field_idents(fields: &syn::punctuated::Punctuated<syn::Field, syn::token::Comma>) -> Vec<&Option<syn::Ident>>
330{
331 fields.iter().map(|field|&field.ident).collect()
332}
333
334fn get_field_types(fields: &syn::punctuated::Punctuated<syn::Field, syn::token::Comma>) -> Vec<&syn::Type>
336{
337 fields.iter().map(|field|&field.ty).collect()
338}
339
340fn get_field_docs(fields: &syn::punctuated::Punctuated<syn::Field, syn::token::Comma>, inner_doc_attr: bool) -> Vec<Option<syn::Attribute>>
342{
343 fields.iter().map(|field| get_inner_docs(&field.attrs, inner_doc_attr)).collect()
344}
345
346fn get_docs(attrs: &[syn::Attribute]) -> (Option<syn::Attribute>, bool)
348{
349 let mut inner_doc_attr = false;
350 if attrs
351 .iter()
352 .any(|assoc_attr|
353 {
354 if assoc_attr.path.is_ident(INNER_DOC_ATTR)
355 {
356 inner_doc_attr = true;
357 }
358 assoc_attr.path.is_ident(DOC_ATTR) || inner_doc_attr
359 })
360 {
361 (attrs.iter()
362 .filter(|assoc_attr| assoc_attr.path.is_ident("doc"))
363 .next()
364 .map(syn::Attribute::clone), inner_doc_attr)
365 }
366 else
367 {
368 (None, inner_doc_attr)
369 }
370}
371
372fn get_inner_docs(attrs: &[syn::Attribute], inner_doc_attr: bool) -> Option<syn::Attribute>
374{
375 attrs.iter()
376 .filter(|assoc_attr| assoc_attr.path.is_ident("doc"))
377 .next()
378 .filter(|_| inner_doc_attr || attrs.iter().any(|attr| attr.path.is_ident("inherit_doc")))
379 .map(syn::Attribute::clone)
380}