• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use proc_macro2::TokenStream;
2 use quote::format_ident;
3 
4 use internals::ast::{Container, Data, Field, Style, Variant};
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, is_packed: bool) -> TokenStream23 pub fn pretend_used(cont: &Container, is_packed: bool) -> TokenStream {
24     let pretend_fields = pretend_fields_used(cont, is_packed);
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: __v0, b: __v1 }) => {}
37 //         _ => {}
38 //     }
39 //
40 // For packed structs on sufficiently new rustc, expands to:
41 //
42 //     match None::<&T> {
43 //         Some(__v @ T { a: _, b: _ }) => {
44 //             let _ = addr_of!(__v.a);
45 //             let _ = addr_of!(__v.b);
46 //         }
47 //         _ => {}
48 //     }
49 //
50 // For packed structs on older rustc, we assume Sized and !Drop, and expand to:
51 //
52 //     match None::<T> {
53 //         Some(T { a: __v0, b: __v1 }) => {}
54 //         _ => {}
55 //     }
56 //
57 // For enums, expands to the following but only including struct variants:
58 //
59 //     match None::<&T> {
60 //         Some(T::A { a: __v0 }) => {}
61 //         Some(T::B { b: __v0 }) => {}
62 //         _ => {}
63 //     }
64 //
pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream65 fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream {
66     match &cont.data {
67         Data::Enum(variants) => pretend_fields_used_enum(cont, variants),
68         Data::Struct(Style::Struct, fields) => {
69             if is_packed {
70                 pretend_fields_used_struct_packed(cont, fields)
71             } else {
72                 pretend_fields_used_struct(cont, fields)
73             }
74         }
75         Data::Struct(_, _) => quote!(),
76     }
77 }
78 
pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream79 fn pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream {
80     let type_ident = &cont.ident;
81     let (_, ty_generics, _) = cont.generics.split_for_impl();
82 
83     let members = fields.iter().map(|field| &field.member);
84     let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
85 
86     quote! {
87         match _serde::__private::None::<&#type_ident #ty_generics> {
88             _serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
89             _ => {}
90         }
91     }
92 }
93 
pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> TokenStream94 fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> TokenStream {
95     let type_ident = &cont.ident;
96     let (_, ty_generics, _) = cont.generics.split_for_impl();
97 
98     let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
99 
100     #[cfg(ptr_addr_of)]
101     {
102         quote! {
103             match _serde::__private::None::<&#type_ident #ty_generics> {
104                 _serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
105                     #(
106                         let _ = _serde::__private::ptr::addr_of!(__v.#members);
107                     )*
108                 }
109                 _ => {}
110             }
111         }
112     }
113 
114     #[cfg(not(ptr_addr_of))]
115     {
116         let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
117 
118         quote! {
119             match _serde::__private::None::<#type_ident #ty_generics> {
120                 _serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
121                 _ => {}
122             }
123         }
124     }
125 }
126 
pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStream127 fn pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStream {
128     let type_ident = &cont.ident;
129     let (_, ty_generics, _) = cont.generics.split_for_impl();
130 
131     let patterns = variants
132         .iter()
133         .filter_map(|variant| match variant.style {
134             Style::Struct => {
135                 let variant_ident = &variant.ident;
136                 let members = variant.fields.iter().map(|field| &field.member);
137                 let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
138                 Some(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* }))
139             }
140             _ => None,
141         })
142         .collect::<Vec<_>>();
143 
144     quote! {
145         match _serde::__private::None::<&#type_ident #ty_generics> {
146             #(
147                 _serde::__private::Some(#patterns) => {}
148             )*
149             _ => {}
150         }
151     }
152 }
153 
154 // Expands to one of these per enum variant:
155 //
156 //     match None {
157 //         Some((__v0, __v1,)) => {
158 //             let _ = E::V { a: __v0, b: __v1 };
159 //         }
160 //         _ => {}
161 //     }
162 //
pretend_variants_used(cont: &Container) -> TokenStream163 fn pretend_variants_used(cont: &Container) -> TokenStream {
164     let variants = match &cont.data {
165         Data::Enum(variants) => variants,
166         Data::Struct(_, _) => {
167             return quote!();
168         }
169     };
170 
171     let type_ident = &cont.ident;
172     let (_, ty_generics, _) = cont.generics.split_for_impl();
173     let turbofish = ty_generics.as_turbofish();
174 
175     let cases = variants.iter().map(|variant| {
176         let variant_ident = &variant.ident;
177         let placeholders = &(0..variant.fields.len())
178             .map(|i| format_ident!("__v{}", i))
179             .collect::<Vec<_>>();
180 
181         let pat = match variant.style {
182             Style::Struct => {
183                 let members = variant.fields.iter().map(|field| &field.member);
184                 quote!({ #(#members: #placeholders),* })
185             }
186             Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )),
187             Style::Unit => quote!(),
188         };
189 
190         quote! {
191             match _serde::__private::None {
192                 _serde::__private::Some((#(#placeholders,)*)) => {
193                     let _ = #type_ident::#variant_ident #turbofish #pat;
194                 }
195                 _ => {}
196             }
197         }
198     });
199 
200     quote!(#(#cases)*)
201 }
202