minetest_protocol_derive/
lib.rs1extern crate proc_macro2;
2extern crate quote;
3extern crate syn;
4
5use proc_macro2::Ident;
6use proc_macro2::Literal;
7use proc_macro2::TokenStream;
8use quote::quote;
9use quote::quote_spanned;
10use quote::ToTokens;
11use syn::parse_macro_input;
12use syn::punctuated::Punctuated;
13use syn::spanned::Spanned;
14use syn::Data;
15use syn::DeriveInput;
16use syn::Field;
17use syn::Generics;
18use syn::Index;
19use syn::Type;
20use syn::TypeParam;
21
22#[proc_macro_derive(MinetestSerialize, attributes(wrap))]
23pub fn minetest_serialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
24 let input = parse_macro_input!(input as DeriveInput);
25 let name = input.ident;
26 let serialize_body = make_serialize_body(&name, &input.data);
27
28 let impl_generic = input.generics.to_token_stream();
31 let name_generic = strip_generic_bounds(&input.generics).to_token_stream();
32 let where_generic = input.generics.where_clause;
33
34 let expanded = quote! {
35 impl #impl_generic Serialize for #name #name_generic #where_generic {
36 type Input = Self;
37 fn serialize<S: Serializer>(value: &Self::Input, ser: &mut S) -> SerializeResult {
38 #serialize_body
39 Ok(())
40 }
41 }
42 };
43 proc_macro::TokenStream::from(expanded)
44}
45
46#[proc_macro_derive(MinetestDeserialize, attributes(wrap))]
47pub fn minetest_deserialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
48 let input = parse_macro_input!(input as DeriveInput);
49 let name = input.ident;
50 let deserialize_body = make_deserialize_body(&name, &input.data);
51
52 let impl_generic = input.generics.to_token_stream();
55 let name_generic = strip_generic_bounds(&input.generics).to_token_stream();
56 let where_generic = input.generics.where_clause;
57
58 let expanded = quote! {
59 impl #impl_generic Deserialize for #name #name_generic #where_generic {
60 type Output = Self;
61 fn deserialize(deser: &mut Deserializer) -> DeserializeResult<Self> {
62 #deserialize_body
63 }
64 }
65 };
66 proc_macro::TokenStream::from(expanded)
67}
68
69fn get_wrapped_type(f: &Field) -> Type {
70 let mut ty = f.ty.clone();
71 for attr in f.attrs.iter() {
72 if attr.path.is_ident("wrap") {
73 ty = attr.parse_args::<Type>().unwrap();
74 }
75 }
76 ty
77}
78
79fn make_serialize_body(input_name: &Ident, data: &Data) -> TokenStream {
82 match *data {
83 syn::Data::Struct(ref data) => match data.fields {
84 syn::Fields::Named(ref fields) => {
85 let recurse = fields.named.iter().map(|f| {
86 let name = &f.ident;
87 let ty = get_wrapped_type(f);
88 quote_spanned! {f.span() =>
89 <#ty as Serialize>::serialize(&value.#name, ser)?;
90 }
91 });
92 quote! {
93 #(#recurse)*
94 }
95 }
96 syn::Fields::Unnamed(ref fields) => {
97 let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
98 let index = Index::from(i);
99 let ty = get_wrapped_type(f);
100 quote_spanned! {f.span() =>
101 <#ty as Serialize>::serialize(&value.#index, ser)?;
102 }
103 });
104 quote! {
105 #(#recurse)*
106 }
107 }
108 syn::Fields::Unit => {
109 quote! {}
110 }
111 },
112 syn::Data::Enum(ref body) => {
113 let recurse = body.variants.iter().enumerate().map(|(i, v)| {
114 if !v.fields.is_empty() {
115 quote_spanned! {v.span() =>
116 compile_error!("Cannot handle fields yet");
117 }
118 } else if v.discriminant.is_some() {
119 quote_spanned! {v.span() =>
120 compile_error!("Cannot handle discrimiant yet");
121 }
122 } else {
123 let id = &v.ident;
124 let i = Literal::u8_unsuffixed(i as u8);
125 quote_spanned! {v.span() =>
126 #id => #i,
127 }
128 }
129 });
130 quote! {
131 use #input_name::*;
132 let tag = match value {
133 #(#recurse)*
134 };
135 u8::serialize(&tag, ser)?;
136 }
137 }
138 syn::Data::Union(_) => unimplemented!(),
139 }
140}
141
142fn make_deserialize_body(input_name: &Ident, data: &Data) -> TokenStream {
143 match *data {
144 syn::Data::Struct(ref data) => {
145 let inner = match data.fields {
146 syn::Fields::Named(ref fields) => {
147 let recurse = fields.named.iter().map(|f| {
148 let name = &f.ident;
149 let ty = get_wrapped_type(f);
150 quote_spanned! {f.span() =>
151 #name: <#ty as Deserialize>::deserialize(deser)?,
152 }
153 });
154 quote! {
155 #(#recurse)*
156 }
157 }
158 syn::Fields::Unnamed(ref fields) => {
159 let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
160 let index = Index::from(i);
161 let ty = get_wrapped_type(f);
162 quote_spanned! {f.span() =>
163 #index: <#ty as Deserialize>::deserialize(deser)?,
164 }
165 });
166 quote! {
167 #(#recurse)*
168 }
169 }
170 syn::Fields::Unit => {
171 quote! {}
172 }
173 };
174 quote! {
175 Ok(Self {
176 #inner
177 })
178 }
179 }
180 syn::Data::Enum(ref body) => {
181 let recurse = body.variants.iter().enumerate().map(|(i, v)| {
182 if !v.fields.is_empty() {
183 quote_spanned! {v.span() =>
184 compile_error!("Cannot handle fields yet");
185 }
186 } else if v.discriminant.is_some() {
187 quote_spanned! {v.span() =>
188 compile_error!("Cannot handle discrimiant yet");
189 }
190 } else {
191 let id = &v.ident;
192 let i = Literal::u8_unsuffixed(i as u8);
193 quote_spanned! {v.span() =>
194 #i => #id,
195
196 }
197 }
198 });
199
200 let input_name_str = Literal::string(&input_name.to_string());
201 quote! {
202 use #input_name::*;
203 let tag = u8::deserialize(deser)?;
204 Ok(match tag {
205 #(#recurse)*
206 _ => bail!("Invalid {} tag: {}", #input_name_str, tag),
207 })
208 }
209 }
210 syn::Data::Union(_) => unimplemented!(),
211 }
212}
213
214fn strip_generic_bounds(input: &Generics) -> Generics {
216 let input = input.clone();
217 Generics {
218 lt_token: input.lt_token,
219 params: {
220 let mut params = input.params.clone();
221 params.iter_mut().for_each(|v| {
222 *v = match v.clone() {
223 syn::GenericParam::Type(v) => syn::GenericParam::Type(TypeParam {
224 attrs: Vec::new(),
225 ident: v.ident.clone(),
226 colon_token: None,
227 bounds: Punctuated::new(),
228 eq_token: None,
229 default: None,
230 }),
231 any => any,
232 }
233 });
234 params
235 },
236 gt_token: input.gt_token,
237 where_clause: None,
238 }
239}