1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
extern crate proc_macro;
use proc_macro::TokenStream;
use quote;
use syn;
#[proc_macro_derive(SampleFunction)]
pub fn derive_sample_function(_item: TokenStream) -> TokenStream {
"fn sample() -> u16 { 18 }".parse().unwrap()
}
#[proc_macro_derive(Describe)]
pub fn describe(input: TokenStream) -> TokenStream {
let syn::DeriveInput { ident, data, .. } = syn::parse_macro_input!(input);
let description = match data {
syn::Data::Struct(s) => match s.fields {
syn::Fields::Named(syn::FieldsNamed { named, .. }) => {
let idents = named.iter().map(|f| &f.ident);
format!(
"a struct with these named fields: {}",
quote::quote! {#(#idents), *}
)
}
syn::Fields::Unnamed(syn::FieldsUnnamed { unnamed, .. }) => {
let num_fields = unnamed.iter().count();
format!("a struct with {} unnamed fields", num_fields)
}
syn::Fields::Unit => format!("a unit struct"),
},
syn::Data::Enum(syn::DataEnum { variants, .. }) => {
let vs = variants.iter().map(|v| &v.ident);
format!("an enum with these variants: {}", quote::quote! {#(#vs),*})
}
syn::Data::Union(syn::DataUnion {
fields: syn::FieldsNamed { named, .. },
..
}) => {
let idents = named.iter().map(|f| &f.ident);
format!(
"a union with these named fields: {}",
quote::quote! {#(#idents),*}
)
}
};
let output = quote::quote! {
impl #ident {
fn describe() -> String { format!("{} is {}.", stringify!(#ident), #description) }
}
};
output.into()
}