]>
Commit | Line | Data |
---|---|---|
c295e0f8 XL |
1 | use proc_macro2::TokenStream; |
2 | use quote::format_ident; | |
8faf50e0 | 3 | |
c295e0f8 | 4 | use internals::ast::{Container, Data, Field, Style, Variant}; |
8faf50e0 XL |
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 | // | |
c295e0f8 XL |
23 | pub fn pretend_used(cont: &Container, is_packed: bool) -> TokenStream { |
24 | let pretend_fields = pretend_fields_used(cont, is_packed); | |
8faf50e0 XL |
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 | // | |
c295e0f8 XL |
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 | // | |
8faf50e0 | 52 | // match None::<T> { |
c295e0f8 | 53 | // Some(T { a: __v0, b: __v1 }) => {} |
8faf50e0 XL |
54 | // _ => {} |
55 | // } | |
56 | // | |
57 | // For enums, expands to the following but only including struct variants: | |
58 | // | |
c295e0f8 XL |
59 | // match None::<&T> { |
60 | // Some(T::A { a: __v0 }) => {} | |
61 | // Some(T::B { b: __v0 }) => {} | |
8faf50e0 XL |
62 | // _ => {} |
63 | // } | |
64 | // | |
c295e0f8 XL |
65 | fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream { |
66 | match &cont.data { | |
67 | Data::Enum(variants) => pretend_fields_used_enum(cont, variants), | |
a2a8927a XL |
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 | } | |
c295e0f8 XL |
75 | Data::Struct(_, _) => quote!(), |
76 | } | |
77 | } | |
78 | ||
79 | fn pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream { | |
8faf50e0 XL |
80 | let type_ident = &cont.ident; |
81 | let (_, ty_generics, _) = cont.generics.split_for_impl(); | |
82 | ||
c295e0f8 XL |
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 | ||
94 | 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 | )* | |
8faf50e0 | 108 | } |
c295e0f8 XL |
109 | _ => {} |
110 | } | |
8faf50e0 | 111 | } |
c295e0f8 XL |
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 | } | |
8faf50e0 | 123 | } |
c295e0f8 XL |
124 | } |
125 | } | |
126 | ||
127 | 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<_>>(); | |
8faf50e0 XL |
143 | |
144 | quote! { | |
c295e0f8 | 145 | match _serde::__private::None::<&#type_ident #ty_generics> { |
8faf50e0 | 146 | #( |
5869c6ff | 147 | _serde::__private::Some(#patterns) => {} |
8faf50e0 XL |
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 | // | |
163 | fn pretend_variants_used(cont: &Container) -> TokenStream { | |
f9f354fc XL |
164 | let variants = match &cont.data { |
165 | Data::Enum(variants) => variants, | |
8faf50e0 XL |
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()) | |
c295e0f8 | 178 | .map(|i| format_ident!("__v{}", i)) |
8faf50e0 XL |
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! { | |
5869c6ff XL |
191 | match _serde::__private::None { |
192 | _serde::__private::Some((#(#placeholders,)*)) => { | |
8faf50e0 XL |
193 | let _ = #type_ident::#variant_ident #turbofish #pat; |
194 | } | |
195 | _ => {} | |
196 | } | |
197 | } | |
198 | }); | |
199 | ||
200 | quote!(#(#cases)*) | |
201 | } |