1 | use crate::internals::ast::{Container, Data, Field, Style, Variant}; |
2 | use proc_macro2::TokenStream; |
3 | use quote::{format_ident, quote}; |
4 | |
5 | // Suppress dead_code warnings that would otherwise appear when using a remote |
6 | // derive. Other than this pretend code, a struct annotated with remote derive |
7 | // never has its fields referenced and an enum annotated with remote derive |
8 | // never has its variants constructed. |
9 | // |
10 | // warning: field is never used: `i` |
11 | // --> src/main.rs:4:20 |
12 | // | |
13 | // 4 | struct StructDef { i: i32 } |
14 | // | ^^^^^^ |
15 | // |
16 | // warning: variant is never constructed: `V` |
17 | // --> src/main.rs:8:16 |
18 | // | |
19 | // 8 | enum EnumDef { V } |
20 | // | ^ |
21 | // |
22 | pub fn pretend_used(cont: &Container, is_packed: bool) -> TokenStream { |
23 | let pretend_fields = pretend_fields_used(cont, is_packed); |
24 | let pretend_variants = pretend_variants_used(cont); |
25 | |
26 | quote! { |
27 | #pretend_fields |
28 | #pretend_variants |
29 | } |
30 | } |
31 | |
32 | // For structs with named fields, expands to: |
33 | // |
34 | // match None::<&T> { |
35 | // Some(T { a: __v0, b: __v1 }) => {} |
36 | // _ => {} |
37 | // } |
38 | // |
39 | // For packed structs on sufficiently new rustc, expands to: |
40 | // |
41 | // match None::<&T> { |
42 | // Some(__v @ T { a: _, b: _ }) => { |
43 | // let _ = addr_of!(__v.a); |
44 | // let _ = addr_of!(__v.b); |
45 | // } |
46 | // _ => {} |
47 | // } |
48 | // |
49 | // For packed structs on older rustc, we assume Sized and !Drop, and expand to: |
50 | // |
51 | // match None::<T> { |
52 | // Some(T { a: __v0, b: __v1 }) => {} |
53 | // _ => {} |
54 | // } |
55 | // |
56 | // For enums, expands to the following but only including struct variants: |
57 | // |
58 | // match None::<&T> { |
59 | // Some(T::A { a: __v0 }) => {} |
60 | // Some(T::B { b: __v0 }) => {} |
61 | // _ => {} |
62 | // } |
63 | // |
64 | fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream { |
65 | match &cont.data { |
66 | Data::Enum(variants) => pretend_fields_used_enum(cont, variants), |
67 | Data::Struct(Style::Struct, fields) => { |
68 | if is_packed { |
69 | pretend_fields_used_struct_packed(cont, fields) |
70 | } else { |
71 | pretend_fields_used_struct(cont, fields) |
72 | } |
73 | } |
74 | Data::Struct(_, _) => quote!(), |
75 | } |
76 | } |
77 | |
78 | fn pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream { |
79 | let type_ident = &cont.ident; |
80 | let (_, ty_generics, _) = cont.generics.split_for_impl(); |
81 | |
82 | let members = fields.iter().map(|field| &field.member); |
83 | let placeholders = (0usize..).map(|i| format_ident!("__v{}" , i)); |
84 | |
85 | quote! { |
86 | match _serde::__private::None::<type_ident #ty_generics> { |
87 | _serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {} |
88 | _ => {} |
89 | } |
90 | } |
91 | } |
92 | |
93 | fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> TokenStream { |
94 | let type_ident = &cont.ident; |
95 | let (_, ty_generics, _) = cont.generics.split_for_impl(); |
96 | |
97 | let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>(); |
98 | |
99 | quote! { |
100 | match _serde::__private::None::<type_ident #ty_generics> { |
101 | _serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => { |
102 | #( |
103 | let _ = _serde::__private::ptr::addr_of!(__v.#members); |
104 | )* |
105 | } |
106 | _ => {} |
107 | } |
108 | } |
109 | } |
110 | |
111 | fn pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStream { |
112 | let type_ident = &cont.ident; |
113 | let (_, ty_generics, _) = cont.generics.split_for_impl(); |
114 | |
115 | let patterns = variants |
116 | .iter() |
117 | .filter_map(|variant| match variant.style { |
118 | Style::Struct => { |
119 | let variant_ident = &variant.ident; |
120 | let members = variant.fields.iter().map(|field| &field.member); |
121 | let placeholders = (0usize..).map(|i| format_ident!("__v{}" , i)); |
122 | Some(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* })) |
123 | } |
124 | _ => None, |
125 | }) |
126 | .collect::<Vec<_>>(); |
127 | |
128 | quote! { |
129 | match _serde::__private::None::<type_ident #ty_generics> { |
130 | #( |
131 | _serde::__private::Some(#patterns) => {} |
132 | )* |
133 | _ => {} |
134 | } |
135 | } |
136 | } |
137 | |
138 | // Expands to one of these per enum variant: |
139 | // |
140 | // match None { |
141 | // Some((__v0, __v1,)) => { |
142 | // let _ = E::V { a: __v0, b: __v1 }; |
143 | // } |
144 | // _ => {} |
145 | // } |
146 | // |
147 | fn pretend_variants_used(cont: &Container) -> TokenStream { |
148 | let variants = match &cont.data { |
149 | Data::Enum(variants) => variants, |
150 | Data::Struct(_, _) => { |
151 | return quote!(); |
152 | } |
153 | }; |
154 | |
155 | let type_ident = &cont.ident; |
156 | let (_, ty_generics, _) = cont.generics.split_for_impl(); |
157 | let turbofish = ty_generics.as_turbofish(); |
158 | |
159 | let cases = variants.iter().map(|variant| { |
160 | let variant_ident = &variant.ident; |
161 | let placeholders = &(0..variant.fields.len()) |
162 | .map(|i| format_ident!("__v{}" , i)) |
163 | .collect::<Vec<_>>(); |
164 | |
165 | let pat = match variant.style { |
166 | Style::Struct => { |
167 | let members = variant.fields.iter().map(|field| &field.member); |
168 | quote!({ #(#members: #placeholders),* }) |
169 | } |
170 | Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )), |
171 | Style::Unit => quote!(), |
172 | }; |
173 | |
174 | quote! { |
175 | match _serde::__private::None { |
176 | _serde::__private::Some((#(#placeholders,)*)) => { |
177 | let _ = #type_ident::#variant_ident #turbofish #pat; |
178 | } |
179 | _ => {} |
180 | } |
181 | } |
182 | }); |
183 | |
184 | quote!(#(#cases)*) |
185 | } |
186 | |