]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_macros/src/serialize.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_macros / src / serialize.rs
CommitLineData
3dfed10e 1use proc_macro2::TokenStream;
a2a8927a 2use quote::{quote, quote_spanned};
3dfed10e 3use syn::parse_quote;
a2a8927a 4use syn::spanned::Spanned;
3dfed10e
XL
5
6pub 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
17pub 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
28pub 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
36fn 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 85fn 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
99pub 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
110pub 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
121pub 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
129fn 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}