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