]>
Commit | Line | Data |
---|---|---|
3dfed10e XL |
1 | use proc_macro2::TokenStream; |
2 | use quote::quote; | |
3 | use syn::parse_quote; | |
4 | ||
5 | pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { | |
6 | let decoder_ty = quote! { __D }; | |
7 | if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { | |
8 | s.add_impl_generic(parse_quote! { 'tcx }); | |
9 | } | |
10 | s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_middle::ty::codec::TyDecoder<'tcx>}); | |
11 | s.add_bounds(synstructure::AddBounds::Generics); | |
12 | ||
13 | decodable_body(s, decoder_ty) | |
14 | } | |
15 | ||
16 | pub fn meta_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { | |
17 | if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { | |
18 | s.add_impl_generic(parse_quote! { 'tcx }); | |
19 | } | |
20 | s.add_impl_generic(parse_quote! { '__a }); | |
21 | let decoder_ty = quote! { DecodeContext<'__a, 'tcx> }; | |
22 | s.add_bounds(synstructure::AddBounds::Generics); | |
23 | ||
24 | decodable_body(s, decoder_ty) | |
25 | } | |
26 | ||
27 | pub fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { | |
28 | let decoder_ty = quote! { __D }; | |
29 | s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_serialize::Decoder}); | |
30 | s.add_bounds(synstructure::AddBounds::Generics); | |
31 | ||
32 | decodable_body(s, decoder_ty) | |
33 | } | |
34 | ||
35 | fn decodable_body( | |
36 | s: synstructure::Structure<'_>, | |
37 | decoder_ty: TokenStream, | |
38 | ) -> proc_macro2::TokenStream { | |
39 | if let syn::Data::Union(_) = s.ast().data { | |
40 | panic!("cannot derive on union") | |
41 | } | |
42 | let ty_name = s.ast().ident.to_string(); | |
43 | let decode_body = match s.variants() { | |
44 | [vi] => { | |
45 | let construct = vi.construct(|field, index| decode_field(field, index, true)); | |
3dfed10e XL |
46 | quote! { |
47 | ::rustc_serialize::Decoder::read_struct( | |
48 | __decoder, | |
3dfed10e XL |
49 | |__decoder| { ::std::result::Result::Ok(#construct) }, |
50 | ) | |
51 | } | |
52 | } | |
53 | variants => { | |
54 | let match_inner: TokenStream = variants | |
55 | .iter() | |
56 | .enumerate() | |
57 | .map(|(idx, vi)| { | |
58 | let construct = vi.construct(|field, index| decode_field(field, index, false)); | |
59 | quote! { #idx => { ::std::result::Result::Ok(#construct) } } | |
60 | }) | |
61 | .collect(); | |
62 | let names: TokenStream = variants | |
63 | .iter() | |
64 | .map(|vi| { | |
65 | let variant_name = vi.ast().ident.to_string(); | |
66 | quote!(#variant_name,) | |
67 | }) | |
68 | .collect(); | |
69 | let message = format!( | |
70 | "invalid enum variant tag while decoding `{}`, expected 0..{}", | |
71 | ty_name, | |
72 | variants.len() | |
73 | ); | |
74 | quote! { | |
75 | ::rustc_serialize::Decoder::read_enum( | |
76 | __decoder, | |
3dfed10e XL |
77 | |__decoder| { |
78 | ::rustc_serialize::Decoder::read_enum_variant( | |
79 | __decoder, | |
80 | &[#names], | |
81 | |__decoder, __variant_idx| { | |
82 | match __variant_idx { | |
83 | #match_inner | |
84 | _ => return ::std::result::Result::Err( | |
85 | ::rustc_serialize::Decoder::error(__decoder, #message)), | |
86 | } | |
87 | }) | |
88 | } | |
89 | ) | |
90 | } | |
91 | } | |
92 | }; | |
93 | ||
94 | s.bound_impl( | |
95 | quote!(::rustc_serialize::Decodable<#decoder_ty>), | |
96 | quote! { | |
97 | fn decode( | |
98 | __decoder: &mut #decoder_ty, | |
99 | ) -> ::std::result::Result<Self, <#decoder_ty as ::rustc_serialize::Decoder>::Error> { | |
100 | #decode_body | |
101 | } | |
102 | }, | |
103 | ) | |
104 | } | |
105 | ||
106 | fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro2::TokenStream { | |
107 | let decode_inner_method = if let syn::Type::Reference(_) = field.ty { | |
108 | quote! { ::rustc_middle::ty::codec::RefDecodable::decode } | |
109 | } else { | |
110 | quote! { ::rustc_serialize::Decodable::decode } | |
111 | }; | |
112 | let (decode_method, opt_field_name) = if is_struct { | |
113 | let field_name = field.ident.as_ref().map_or_else(|| index.to_string(), |i| i.to_string()); | |
114 | ( | |
115 | proc_macro2::Ident::new("read_struct_field", proc_macro2::Span::call_site()), | |
116 | quote! { #field_name, }, | |
117 | ) | |
118 | } else { | |
119 | ( | |
120 | proc_macro2::Ident::new("read_enum_variant_arg", proc_macro2::Span::call_site()), | |
121 | quote! {}, | |
122 | ) | |
123 | }; | |
124 | ||
125 | quote! { | |
126 | match ::rustc_serialize::Decoder::#decode_method( | |
17df50a5 | 127 | __decoder, #opt_field_name #decode_inner_method) { |
3dfed10e XL |
128 | ::std::result::Result::Ok(__res) => __res, |
129 | ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err), | |
130 | } | |
131 | } | |
132 | } | |
133 | ||
134 | pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { | |
135 | if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { | |
136 | s.add_impl_generic(parse_quote! {'tcx}); | |
137 | } | |
138 | let encoder_ty = quote! { __E }; | |
139 | s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_middle::ty::codec::TyEncoder<'tcx>}); | |
140 | s.add_bounds(synstructure::AddBounds::Generics); | |
141 | ||
142 | encodable_body(s, encoder_ty, false) | |
143 | } | |
144 | ||
145 | pub fn meta_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { | |
146 | if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { | |
147 | s.add_impl_generic(parse_quote! {'tcx}); | |
148 | } | |
149 | s.add_impl_generic(parse_quote! { '__a }); | |
150 | let encoder_ty = quote! { EncodeContext<'__a, 'tcx> }; | |
151 | s.add_bounds(synstructure::AddBounds::Generics); | |
152 | ||
153 | encodable_body(s, encoder_ty, true) | |
154 | } | |
155 | ||
156 | pub fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { | |
157 | let encoder_ty = quote! { __E }; | |
158 | s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder}); | |
159 | s.add_bounds(synstructure::AddBounds::Generics); | |
160 | ||
161 | encodable_body(s, encoder_ty, false) | |
162 | } | |
163 | ||
164 | fn encodable_body( | |
165 | mut s: synstructure::Structure<'_>, | |
166 | encoder_ty: TokenStream, | |
167 | allow_unreachable_code: bool, | |
168 | ) -> proc_macro2::TokenStream { | |
169 | if let syn::Data::Union(_) = s.ast().data { | |
170 | panic!("cannot derive on union") | |
171 | } | |
172 | ||
173 | s.bind_with(|binding| { | |
174 | // Handle the lack of a blanket reference impl. | |
175 | if let syn::Type::Reference(_) = binding.ast().ty { | |
176 | synstructure::BindStyle::Move | |
177 | } else { | |
178 | synstructure::BindStyle::Ref | |
179 | } | |
180 | }); | |
181 | ||
3dfed10e XL |
182 | let encode_body = match s.variants() { |
183 | [_] => { | |
184 | let mut field_idx = 0usize; | |
185 | let encode_inner = s.each_variant(|vi| { | |
186 | vi.bindings() | |
187 | .iter() | |
188 | .map(|binding| { | |
189 | let bind_ident = &binding.binding; | |
190 | let field_name = binding | |
191 | .ast() | |
192 | .ident | |
193 | .as_ref() | |
194 | .map_or_else(|| field_idx.to_string(), |i| i.to_string()); | |
17df50a5 | 195 | let first = field_idx == 0; |
3dfed10e XL |
196 | let result = quote! { |
197 | match ::rustc_serialize::Encoder::emit_struct_field( | |
198 | __encoder, | |
199 | #field_name, | |
17df50a5 | 200 | #first, |
3dfed10e | 201 | |__encoder| |
5869c6ff | 202 | ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder), |
3dfed10e XL |
203 | ) { |
204 | ::std::result::Result::Ok(()) => (), | |
205 | ::std::result::Result::Err(__err) | |
206 | => return ::std::result::Result::Err(__err), | |
207 | } | |
208 | }; | |
209 | field_idx += 1; | |
210 | result | |
211 | }) | |
212 | .collect::<TokenStream>() | |
213 | }); | |
17df50a5 | 214 | let no_fields = field_idx == 0; |
3dfed10e | 215 | quote! { |
17df50a5 | 216 | ::rustc_serialize::Encoder::emit_struct(__encoder, #no_fields, |__encoder| { |
3dfed10e XL |
217 | ::std::result::Result::Ok(match *self { #encode_inner }) |
218 | }) | |
219 | } | |
220 | } | |
221 | _ => { | |
222 | let mut variant_idx = 0usize; | |
223 | let encode_inner = s.each_variant(|vi| { | |
224 | let variant_name = vi.ast().ident.to_string(); | |
225 | let mut field_idx = 0usize; | |
226 | ||
227 | let encode_fields: TokenStream = vi | |
228 | .bindings() | |
229 | .iter() | |
230 | .map(|binding| { | |
231 | let bind_ident = &binding.binding; | |
17df50a5 | 232 | let first = field_idx == 0; |
3dfed10e XL |
233 | let result = quote! { |
234 | match ::rustc_serialize::Encoder::emit_enum_variant_arg( | |
235 | __encoder, | |
17df50a5 | 236 | #first, |
3dfed10e | 237 | |__encoder| |
5869c6ff | 238 | ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder), |
3dfed10e XL |
239 | ) { |
240 | ::std::result::Result::Ok(()) => (), | |
241 | ::std::result::Result::Err(__err) | |
242 | => return ::std::result::Result::Err(__err), | |
243 | } | |
244 | }; | |
245 | field_idx += 1; | |
246 | result | |
247 | }) | |
248 | .collect(); | |
249 | ||
3c0e092e XL |
250 | let result = if field_idx != 0 { |
251 | quote! { | |
252 | ::rustc_serialize::Encoder::emit_enum_variant( | |
253 | __encoder, | |
254 | #variant_name, | |
255 | #variant_idx, | |
256 | #field_idx, | |
257 | |__encoder| { ::std::result::Result::Ok({ #encode_fields }) } | |
258 | ) | |
259 | } | |
260 | } else { | |
261 | quote! { | |
262 | ::rustc_serialize::Encoder::emit_fieldless_enum_variant::<#variant_idx>( | |
263 | __encoder, | |
264 | #variant_name, | |
265 | ) | |
266 | } | |
267 | }; | |
3dfed10e XL |
268 | variant_idx += 1; |
269 | result | |
270 | }); | |
271 | quote! { | |
17df50a5 | 272 | ::rustc_serialize::Encoder::emit_enum(__encoder, |__encoder| { |
3dfed10e XL |
273 | match *self { |
274 | #encode_inner | |
275 | } | |
276 | }) | |
277 | } | |
278 | } | |
279 | }; | |
280 | ||
281 | let lints = if allow_unreachable_code { | |
282 | quote! { #![allow(unreachable_code)] } | |
283 | } else { | |
284 | quote! {} | |
285 | }; | |
286 | ||
287 | s.bound_impl( | |
288 | quote!(::rustc_serialize::Encodable<#encoder_ty>), | |
289 | quote! { | |
290 | fn encode( | |
291 | &self, | |
292 | __encoder: &mut #encoder_ty, | |
293 | ) -> ::std::result::Result<(), <#encoder_ty as ::rustc_serialize::Encoder>::Error> { | |
294 | #lints | |
295 | #encode_body | |
296 | } | |
297 | }, | |
298 | ) | |
299 | } |