frame_support_procedural_tools_derive/
lib.rs
1use proc_macro::TokenStream;
23use proc_macro2::Span;
24use quote::quote;
25use syn::parse_macro_input;
26
27pub(crate) fn fields_idents(
28 fields: impl Iterator<Item = syn::Field>,
29) -> impl Iterator<Item = proc_macro2::TokenStream> {
30 fields.enumerate().map(|(ix, field)| {
31 field.ident.map(|i| quote! {#i}).unwrap_or_else(|| {
32 let f_ix: syn::Ident = syn::Ident::new(&format!("f_{}", ix), Span::call_site());
33 quote!( #f_ix )
34 })
35 })
36}
37
38pub(crate) fn fields_access(
39 fields: impl Iterator<Item = syn::Field>,
40) -> impl Iterator<Item = proc_macro2::TokenStream> {
41 fields.enumerate().map(|(ix, field)| {
42 field.ident.map(|i| quote!( #i )).unwrap_or_else(|| {
43 let f_ix: syn::Index = syn::Index { index: ix as u32, span: Span::call_site() };
44 quote!( #f_ix )
45 })
46 })
47}
48
49#[proc_macro_derive(Parse)]
53pub fn derive_parse(input: TokenStream) -> TokenStream {
54 let item = parse_macro_input!(input as syn::Item);
55 match item {
56 syn::Item::Struct(input) => derive_parse_struct(input),
57 _ => TokenStream::new(), }
59}
60
61fn derive_parse_struct(input: syn::ItemStruct) -> TokenStream {
62 let syn::ItemStruct { ident, generics, fields, .. } = input;
63 let field_names = {
64 let name = fields_idents(fields.iter().map(Clone::clone));
65 quote! {
66 #(
67 #name,
68 )*
69 }
70 };
71 let field = fields_idents(fields.iter().map(Clone::clone));
72 let tokens = quote! {
73 impl #generics syn::parse::Parse for #ident #generics {
74 fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
75 #(
76 let #field = input.parse()?;
77 )*
78 Ok(Self {
79 #field_names
80 })
81 }
82 }
83 };
84 tokens.into()
85}
86
87#[proc_macro_derive(ToTokens)]
93pub fn derive_totokens(input: TokenStream) -> TokenStream {
94 let item = parse_macro_input!(input as syn::Item);
95 match item {
96 syn::Item::Enum(input) => derive_totokens_enum(input),
97 syn::Item::Struct(input) => derive_totokens_struct(input),
98 _ => TokenStream::new(), }
100}
101
102fn derive_totokens_struct(input: syn::ItemStruct) -> TokenStream {
103 let syn::ItemStruct { ident, generics, fields, .. } = input;
104
105 let fields = fields_access(fields.iter().map(Clone::clone));
106 let tokens = quote! {
107
108 impl #generics quote::ToTokens for #ident #generics {
109 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
110 #(
111 self.#fields.to_tokens(tokens);
112 )*
113 }
114 }
115
116 };
117 tokens.into()
118}
119
120fn derive_totokens_enum(input: syn::ItemEnum) -> TokenStream {
121 let syn::ItemEnum { ident, generics, variants, .. } = input;
122 let variants = variants.iter().map(|v| {
123 let v_ident = v.ident.clone();
124 let fields_build = if v.fields.iter().count() > 0 {
125 let fields_id = fields_idents(v.fields.iter().map(Clone::clone));
126 quote!( (#(#fields_id), *) )
127 } else {
128 quote!()
129 };
130 let field = fields_idents(v.fields.iter().map(Clone::clone));
131 quote! {
132 #ident::#v_ident #fields_build => {
133 #(
134 #field.to_tokens(tokens);
135 )*
136 },
137 }
138 });
139 let tokens = quote! {
140 impl #generics quote::ToTokens for #ident #generics {
141 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
142 match self {
143 #(
144 #variants
145 )*
146 }
147 }
148 }
149 };
150
151 tokens.into()
152}