serde_derive/
pretend.rs

1use crate::internals::ast::{Container, Data, Field, Style, Variant};
2use crate::private;
3use proc_macro2::TokenStream;
4use quote::{format_ident, quote};
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//
23pub 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//
65fn 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 | Style::Tuple | Style::Newtype, 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(Style::Unit, _) => quote!(),
76    }
77}
78
79fn 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
94fn 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    let private2 = private;
101    quote! {
102        match _serde::#private::None::<&#type_ident #ty_generics> {
103            _serde::#private::Some(__v @ #type_ident { #(#members: _),* }) => {
104                #(
105                    let _ = _serde::#private2::ptr::addr_of!(__v.#members);
106                )*
107            }
108            _ => {}
109        }
110    }
111}
112
113fn pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStream {
114    let type_ident = &cont.ident;
115    let (_, ty_generics, _) = cont.generics.split_for_impl();
116
117    let patterns = variants
118        .iter()
119        .filter_map(|variant| match variant.style {
120            Style::Struct | Style::Tuple | Style::Newtype => {
121                let variant_ident = &variant.ident;
122                let members = variant.fields.iter().map(|field| &field.member);
123                let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
124                Some(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* }))
125            }
126            Style::Unit => None,
127        })
128        .collect::<Vec<_>>();
129
130    let private2 = private;
131    quote! {
132        match _serde::#private::None::<&#type_ident #ty_generics> {
133            #(
134                _serde::#private2::Some(#patterns) => {}
135            )*
136            _ => {}
137        }
138    }
139}
140
141// Expands to one of these per enum variant:
142//
143//     match None {
144//         Some((__v0, __v1,)) => {
145//             let _ = E::V { a: __v0, b: __v1 };
146//         }
147//         _ => {}
148//     }
149//
150fn pretend_variants_used(cont: &Container) -> TokenStream {
151    let variants = match &cont.data {
152        Data::Enum(variants) => variants,
153        Data::Struct(_, _) => {
154            return quote!();
155        }
156    };
157
158    let type_ident = &cont.ident;
159    let (_, ty_generics, _) = cont.generics.split_for_impl();
160    let turbofish = ty_generics.as_turbofish();
161
162    let cases = variants.iter().map(|variant| {
163        let variant_ident = &variant.ident;
164        let placeholders = &(0..variant.fields.len())
165            .map(|i| format_ident!("__v{}", i))
166            .collect::<Vec<_>>();
167
168        let pat = match variant.style {
169            Style::Struct => {
170                let members = variant.fields.iter().map(|field| &field.member);
171                quote!({ #(#members: #placeholders),* })
172            }
173            Style::Tuple | Style::Newtype => quote!(( #(#placeholders),* )),
174            Style::Unit => quote!(),
175        };
176
177        quote! {
178            match _serde::#private::None {
179                _serde::#private::Some((#(#placeholders,)*)) => {
180                    let _ = #type_ident::#variant_ident #turbofish #pat;
181                }
182                _ => {}
183            }
184        }
185    });
186
187    quote!(#(#cases)*)
188}