1 use proc_macro2::{Span, TokenStream};
2 use syn::Ident;
3 
4 use internals::ast::{Container, Data, Field, Style};
5 
6 // Suppress dead_code warnings that would otherwise appear when using a remote
7 // derive. Other than this pretend code, a struct annotated with remote derive
8 // never has its fields referenced and an enum annotated with remote derive
9 // never has its variants constructed.
10 //
11 //     warning: field is never used: `i`
12 //      --> src/main.rs:4:20
13 //       |
14 //     4 | struct StructDef { i: i32 }
15 //       |                    ^^^^^^
16 //
17 //     warning: variant is never constructed: `V`
18 //      --> src/main.rs:8:16
19 //       |
20 //     8 | enum EnumDef { V }
21 //       |                ^
22 //
pretend_used(cont: &Container) -> TokenStream23 pub fn pretend_used(cont: &Container) -> TokenStream {
24     let pretend_fields = pretend_fields_used(cont);
25     let pretend_variants = pretend_variants_used(cont);
26 
27     quote! {
28         #pretend_fields
29         #pretend_variants
30     }
31 }
32 
33 // For structs with named fields, expands to:
34 //
35 //     match None::<T> {
36 //         Some(T { a: ref __v0, b: ref __v1 }) => {}
37 //         _ => {}
38 //     }
39 //
40 // For enums, expands to the following but only including struct variants:
41 //
42 //     match None::<T> {
43 //         Some(T::A { a: ref __v0 }) => {}
44 //         Some(T::B { b: ref __v0 }) => {}
45 //         _ => {}
46 //     }
47 //
48 // The `ref` is important in case the user has written a Drop impl on their
49 // type. Rust does not allow destructuring a struct or enum that has a Drop
50 // impl.
pretend_fields_used(cont: &Container) -> TokenStream51 fn pretend_fields_used(cont: &Container) -> TokenStream {
52     let type_ident = &cont.ident;
53     let (_, ty_generics, _) = cont.generics.split_for_impl();
54 
55     let patterns = match &cont.data {
56         Data::Enum(variants) => variants
57             .iter()
58             .filter_map(|variant| match variant.style {
59                 Style::Struct => {
60                     let variant_ident = &variant.ident;
61                     let pat = struct_pattern(&variant.fields);
62                     Some(quote!(#type_ident::#variant_ident #pat))
63                 }
64                 _ => None,
65             })
66             .collect::<Vec<_>>(),
67         Data::Struct(Style::Struct, fields) => {
68             let pat = struct_pattern(fields);
69             vec![quote!(#type_ident #pat)]
70         }
71         Data::Struct(_, _) => {
72             return quote!();
73         }
74     };
75 
76     quote! {
77         match _serde::export::None::<#type_ident #ty_generics> {
78             #(
79                 _serde::export::Some(#patterns) => {}
80             )*
81             _ => {}
82         }
83     }
84 }
85 
86 // Expands to one of these per enum variant:
87 //
88 //     match None {
89 //         Some((__v0, __v1,)) => {
90 //             let _ = E::V { a: __v0, b: __v1 };
91 //         }
92 //         _ => {}
93 //     }
94 //
pretend_variants_used(cont: &Container) -> TokenStream95 fn pretend_variants_used(cont: &Container) -> TokenStream {
96     let variants = match &cont.data {
97         Data::Enum(variants) => variants,
98         Data::Struct(_, _) => {
99             return quote!();
100         }
101     };
102 
103     let type_ident = &cont.ident;
104     let (_, ty_generics, _) = cont.generics.split_for_impl();
105     let turbofish = ty_generics.as_turbofish();
106 
107     let cases = variants.iter().map(|variant| {
108         let variant_ident = &variant.ident;
109         let placeholders = &(0..variant.fields.len())
110             .map(|i| Ident::new(&format!("__v{}", i), Span::call_site()))
111             .collect::<Vec<_>>();
112 
113         let pat = match variant.style {
114             Style::Struct => {
115                 let members = variant.fields.iter().map(|field| &field.member);
116                 quote!({ #(#members: #placeholders),* })
117             }
118             Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )),
119             Style::Unit => quote!(),
120         };
121 
122         quote! {
123             match _serde::export::None {
124                 _serde::export::Some((#(#placeholders,)*)) => {
125                     let _ = #type_ident::#variant_ident #turbofish #pat;
126                 }
127                 _ => {}
128             }
129         }
130     });
131 
132     quote!(#(#cases)*)
133 }
134 
struct_pattern(fields: &[Field]) -> TokenStream135 fn struct_pattern(fields: &[Field]) -> TokenStream {
136     let members = fields.iter().map(|field| &field.member);
137     let placeholders =
138         (0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site()));
139     quote!({ #(#members: ref #placeholders),* })
140 }
141