]>
Commit | Line | Data |
---|---|---|
3dfed10e | 1 | use proc_macro2::TokenStream; |
a2a8927a | 2 | use quote::{quote, quote_spanned}; |
3dfed10e | 3 | use syn::parse_quote; |
a2a8927a | 4 | use syn::spanned::Spanned; |
3dfed10e XL |
5 | |
6 | pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { | |
7 | let decoder_ty = quote! { __D }; | |
8 | if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { | |
9 | s.add_impl_generic(parse_quote! { 'tcx }); | |
10 | } | |
923072b8 | 11 | s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_type_ir::codec::TyDecoder<I = ::rustc_middle::ty::TyCtxt<'tcx>>}); |
3dfed10e XL |
12 | s.add_bounds(synstructure::AddBounds::Generics); |
13 | ||
14 | decodable_body(s, decoder_ty) | |
15 | } | |
16 | ||
17 | pub fn meta_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { | |
18 | if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { | |
19 | s.add_impl_generic(parse_quote! { 'tcx }); | |
20 | } | |
21 | s.add_impl_generic(parse_quote! { '__a }); | |
22 | let decoder_ty = quote! { DecodeContext<'__a, 'tcx> }; | |
23 | s.add_bounds(synstructure::AddBounds::Generics); | |
24 | ||
25 | decodable_body(s, decoder_ty) | |
26 | } | |
27 | ||
28 | pub fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { | |
29 | let decoder_ty = quote! { __D }; | |
30 | s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_serialize::Decoder}); | |
31 | s.add_bounds(synstructure::AddBounds::Generics); | |
32 | ||
33 | decodable_body(s, decoder_ty) | |
34 | } | |
35 | ||
36 | fn decodable_body( | |
37 | s: synstructure::Structure<'_>, | |
38 | decoder_ty: TokenStream, | |
39 | ) -> proc_macro2::TokenStream { | |
40 | if let syn::Data::Union(_) = s.ast().data { | |
41 | panic!("cannot derive on union") | |
42 | } | |
43 | let ty_name = s.ast().ident.to_string(); | |
44 | let decode_body = match s.variants() { | |
9ffffee4 FG |
45 | [] => { |
46 | let message = format!("`{}` has no variants to decode", ty_name); | |
47 | quote! { | |
48 | panic!(#message) | |
49 | } | |
50 | } | |
5e7ed085 | 51 | [vi] => vi.construct(|field, _index| decode_field(field)), |
3dfed10e XL |
52 | variants => { |
53 | let match_inner: TokenStream = variants | |
54 | .iter() | |
55 | .enumerate() | |
56 | .map(|(idx, vi)| { | |
5e7ed085 | 57 | let construct = vi.construct(|field, _index| decode_field(field)); |
5099ac24 | 58 | quote! { #idx => { #construct } } |
3dfed10e XL |
59 | }) |
60 | .collect(); | |
3dfed10e XL |
61 | let message = format!( |
62 | "invalid enum variant tag while decoding `{}`, expected 0..{}", | |
63 | ty_name, | |
64 | variants.len() | |
65 | ); | |
66 | quote! { | |
5e7ed085 FG |
67 | match ::rustc_serialize::Decoder::read_usize(__decoder) { |
68 | #match_inner | |
69 | _ => panic!(#message), | |
70 | } | |
3dfed10e XL |
71 | } |
72 | } | |
73 | }; | |
74 | ||
75 | s.bound_impl( | |
76 | quote!(::rustc_serialize::Decodable<#decoder_ty>), | |
77 | quote! { | |
5099ac24 | 78 | fn decode(__decoder: &mut #decoder_ty) -> Self { |
3dfed10e XL |
79 | #decode_body |
80 | } | |
81 | }, | |
82 | ) | |
83 | } | |
84 | ||
5e7ed085 | 85 | fn decode_field(field: &syn::Field) -> proc_macro2::TokenStream { |
a2a8927a XL |
86 | let field_span = field.ident.as_ref().map_or(field.ty.span(), |ident| ident.span()); |
87 | ||
3dfed10e XL |
88 | let decode_inner_method = if let syn::Type::Reference(_) = field.ty { |
89 | quote! { ::rustc_middle::ty::codec::RefDecodable::decode } | |
90 | } else { | |
91 | quote! { ::rustc_serialize::Decodable::decode } | |
92 | }; | |
a2a8927a XL |
93 | let __decoder = quote! { __decoder }; |
94 | // Use the span of the field for the method call, so | |
95 | // that backtraces will point to the field. | |
5e7ed085 | 96 | quote_spanned! {field_span=> #decode_inner_method(#__decoder) } |
3dfed10e XL |
97 | } |
98 | ||
99 | pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { | |
100 | if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { | |
101 | s.add_impl_generic(parse_quote! {'tcx}); | |
102 | } | |
103 | let encoder_ty = quote! { __E }; | |
923072b8 | 104 | s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_type_ir::codec::TyEncoder<I = ::rustc_middle::ty::TyCtxt<'tcx>>}); |
3dfed10e XL |
105 | s.add_bounds(synstructure::AddBounds::Generics); |
106 | ||
107 | encodable_body(s, encoder_ty, false) | |
108 | } | |
109 | ||
110 | pub fn meta_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { | |
111 | if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { | |
112 | s.add_impl_generic(parse_quote! {'tcx}); | |
113 | } | |
114 | s.add_impl_generic(parse_quote! { '__a }); | |
115 | let encoder_ty = quote! { EncodeContext<'__a, 'tcx> }; | |
116 | s.add_bounds(synstructure::AddBounds::Generics); | |
117 | ||
118 | encodable_body(s, encoder_ty, true) | |
119 | } | |
120 | ||
121 | pub fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { | |
122 | let encoder_ty = quote! { __E }; | |
123 | s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder}); | |
124 | s.add_bounds(synstructure::AddBounds::Generics); | |
125 | ||
126 | encodable_body(s, encoder_ty, false) | |
127 | } | |
128 | ||
129 | fn encodable_body( | |
130 | mut s: synstructure::Structure<'_>, | |
131 | encoder_ty: TokenStream, | |
132 | allow_unreachable_code: bool, | |
133 | ) -> proc_macro2::TokenStream { | |
134 | if let syn::Data::Union(_) = s.ast().data { | |
135 | panic!("cannot derive on union") | |
136 | } | |
137 | ||
138 | s.bind_with(|binding| { | |
139 | // Handle the lack of a blanket reference impl. | |
140 | if let syn::Type::Reference(_) = binding.ast().ty { | |
141 | synstructure::BindStyle::Move | |
142 | } else { | |
143 | synstructure::BindStyle::Ref | |
144 | } | |
145 | }); | |
146 | ||
3dfed10e | 147 | let encode_body = match s.variants() { |
9ffffee4 FG |
148 | [] => { |
149 | quote! { | |
150 | match *self {} | |
151 | } | |
152 | } | |
3dfed10e | 153 | [_] => { |
3dfed10e XL |
154 | let encode_inner = s.each_variant(|vi| { |
155 | vi.bindings() | |
156 | .iter() | |
157 | .map(|binding| { | |
158 | let bind_ident = &binding.binding; | |
3dfed10e | 159 | let result = quote! { |
923072b8 FG |
160 | ::rustc_serialize::Encodable::<#encoder_ty>::encode( |
161 | #bind_ident, | |
3dfed10e | 162 | __encoder, |
923072b8 | 163 | ); |
3dfed10e | 164 | }; |
3dfed10e XL |
165 | result |
166 | }) | |
167 | .collect::<TokenStream>() | |
168 | }); | |
169 | quote! { | |
923072b8 | 170 | match *self { #encode_inner } |
3dfed10e XL |
171 | } |
172 | } | |
173 | _ => { | |
9ffffee4 FG |
174 | let disc = { |
175 | let mut variant_idx = 0usize; | |
176 | let encode_inner = s.each_variant(|_| { | |
177 | let result = quote! { | |
178 | #variant_idx | |
179 | }; | |
180 | variant_idx += 1; | |
181 | result | |
182 | }); | |
183 | quote! { | |
184 | let disc = match *self { | |
185 | #encode_inner | |
186 | }; | |
187 | ::rustc_serialize::Encoder::emit_usize(__encoder, disc); | |
188 | } | |
189 | }; | |
190 | ||
3dfed10e XL |
191 | let mut variant_idx = 0usize; |
192 | let encode_inner = s.each_variant(|vi| { | |
3dfed10e XL |
193 | let encode_fields: TokenStream = vi |
194 | .bindings() | |
195 | .iter() | |
196 | .map(|binding| { | |
197 | let bind_ident = &binding.binding; | |
198 | let result = quote! { | |
923072b8 FG |
199 | ::rustc_serialize::Encodable::<#encoder_ty>::encode( |
200 | #bind_ident, | |
3dfed10e | 201 | __encoder, |
923072b8 | 202 | ); |
3dfed10e | 203 | }; |
3dfed10e XL |
204 | result |
205 | }) | |
206 | .collect(); | |
3dfed10e | 207 | variant_idx += 1; |
9ffffee4 | 208 | encode_fields |
3dfed10e XL |
209 | }); |
210 | quote! { | |
9ffffee4 | 211 | #disc |
923072b8 FG |
212 | match *self { |
213 | #encode_inner | |
214 | } | |
3dfed10e XL |
215 | } |
216 | } | |
217 | }; | |
218 | ||
219 | let lints = if allow_unreachable_code { | |
220 | quote! { #![allow(unreachable_code)] } | |
221 | } else { | |
222 | quote! {} | |
223 | }; | |
224 | ||
225 | s.bound_impl( | |
226 | quote!(::rustc_serialize::Encodable<#encoder_ty>), | |
227 | quote! { | |
228 | fn encode( | |
229 | &self, | |
230 | __encoder: &mut #encoder_ty, | |
923072b8 | 231 | ) { |
3dfed10e XL |
232 | #lints |
233 | #encode_body | |
234 | } | |
235 | }, | |
236 | ) | |
237 | } |