1 use proc_macro2::TokenStream;
2 use quote::quote;
3 use syn::parse_quote;
4 
type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream5 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 
meta_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream16 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 
decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream27 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 
decodable_body( s: synstructure::Structure<'_>, decoder_ty: TokenStream, ) -> proc_macro2::TokenStream35 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));
46             quote! {
47                 ::rustc_serialize::Decoder::read_struct(
48                     __decoder,
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,
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 
decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro2::TokenStream106 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(
127             __decoder, #opt_field_name #decode_inner_method) {
128             ::std::result::Result::Ok(__res) => __res,
129             ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err),
130         }
131     }
132 }
133 
type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream134 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 
meta_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream145 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 
encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream156 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 
encodable_body( mut s: synstructure::Structure<'_>, encoder_ty: TokenStream, allow_unreachable_code: bool, ) -> proc_macro2::TokenStream164 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 
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());
195                         let first = field_idx == 0;
196                         let result = quote! {
197                             match ::rustc_serialize::Encoder::emit_struct_field(
198                                 __encoder,
199                                 #field_name,
200                                 #first,
201                                 |__encoder|
202                                 ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
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             });
214             let no_fields = field_idx == 0;
215             quote! {
216                 ::rustc_serialize::Encoder::emit_struct(__encoder, #no_fields, |__encoder| {
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;
232                         let first = field_idx == 0;
233                         let result = quote! {
234                             match ::rustc_serialize::Encoder::emit_enum_variant_arg(
235                                 __encoder,
236                                 #first,
237                                 |__encoder|
238                                 ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
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 
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                 };
268                 variant_idx += 1;
269                 result
270             });
271             quote! {
272                 ::rustc_serialize::Encoder::emit_enum(__encoder, |__encoder| {
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 }
300