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