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