1 use proc_macro2::TokenStream;
2 use quote::{quote, quote_spanned};
4 use syn::spanned::Spanned;
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 });
11 s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_type_ir::codec::TyDecoder<I = ::rustc_middle::ty::TyCtxt<'tcx>>});
12 s.add_bounds(synstructure::AddBounds::Generics);
14 decodable_body(s, decoder_ty)
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 });
21 s.add_impl_generic(parse_quote! { '__a });
22 let decoder_ty = quote! { DecodeContext<'__a, 'tcx> };
23 s.add_bounds(synstructure::AddBounds::Generics);
25 decodable_body(s, decoder_ty)
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);
33 decodable_body(s, decoder_ty)
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")
43 let ty_name = s.ast().ident.to_string();
44 let decode_body = match s.variants() {
45 [vi] => vi.construct(|field, _index| decode_field(field)),
47 let match_inner: TokenStream = variants
51 let construct = vi.construct(|field, _index| decode_field(field));
52 quote! { #idx => { #construct } }
55 let message = format!(
56 "invalid enum variant tag while decoding `{}`, expected 0..{}",
61 match ::rustc_serialize::Decoder::read_usize(__decoder) {
63 _ => panic!(#message),
70 quote!(::rustc_serialize::Decodable<#decoder_ty>),
72 fn decode(__decoder: &mut #decoder_ty) -> Self {
79 fn decode_field(field: &syn::Field) -> proc_macro2::TokenStream {
80 let field_span = field.ident.as_ref().map_or(field.ty.span(), |ident| ident.span());
82 let decode_inner_method = if let syn::Type::Reference(_) = field.ty {
83 quote! { ::rustc_middle::ty::codec::RefDecodable::decode }
85 quote! { ::rustc_serialize::Decodable::decode }
87 let __decoder = quote! { __decoder };
88 // Use the span of the field for the method call, so
89 // that backtraces will point to the field.
90 quote_spanned! {field_span=> #decode_inner_method(#__decoder) }
93 pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
94 if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
95 s.add_impl_generic(parse_quote! {'tcx});
97 let encoder_ty = quote! { __E };
98 s.add_impl_generic(parse_quote! {#encoder_ty: ::rustc_type_ir::codec::TyEncoder<I = ::rustc_middle::ty::TyCtxt<'tcx>>});
99 s.add_bounds(synstructure::AddBounds::Generics);
101 encodable_body(s, encoder_ty, false)
104 pub fn meta_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
105 if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
106 s.add_impl_generic(parse_quote! {'tcx});
108 s.add_impl_generic(parse_quote! { '__a });
109 let encoder_ty = quote! { EncodeContext<'__a, 'tcx> };
110 s.add_bounds(synstructure::AddBounds::Generics);
112 encodable_body(s, encoder_ty, true)
115 pub fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
116 let encoder_ty = quote! { __E };
117 s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder});
118 s.add_bounds(synstructure::AddBounds::Generics);
120 encodable_body(s, encoder_ty, false)
124 mut s: synstructure::Structure<'_>,
125 encoder_ty: TokenStream,
126 allow_unreachable_code: bool,
127 ) -> proc_macro2::TokenStream {
128 if let syn::Data::Union(_) = s.ast().data {
129 panic!("cannot derive on union")
132 s.bind_with(|binding| {
133 // Handle the lack of a blanket reference impl.
134 if let syn::Type::Reference(_) = binding.ast().ty {
135 synstructure::BindStyle::Move
137 synstructure::BindStyle::Ref
141 let encode_body = match s.variants() {
143 let encode_inner = s.each_variant(|vi| {
147 let bind_ident = &binding.binding;
148 let result = quote! {
149 ::rustc_serialize::Encodable::<#encoder_ty>::encode(
156 .collect::<TokenStream>()
159 match *self { #encode_inner }
163 let mut variant_idx = 0usize;
164 let encode_inner = s.each_variant(|vi| {
165 let encode_fields: TokenStream = vi
169 let bind_ident = &binding.binding;
170 let result = quote! {
171 ::rustc_serialize::Encodable::<#encoder_ty>::encode(
180 let result = if !vi.bindings().is_empty() {
182 ::rustc_serialize::Encoder::emit_enum_variant(
185 |__encoder| { #encode_fields }
190 ::rustc_serialize::Encoder::emit_fieldless_enum_variant::<#variant_idx>(
206 let lints = if allow_unreachable_code {
207 quote! { #![allow(unreachable_code)] }
213 quote!(::rustc_serialize::Encodable<#encoder_ty>),
217 __encoder: &mut #encoder_ty,