Avoid generating ref patterns for fields of packed remote struct

This commit is contained in:
David Tolnay 2021-08-23 10:17:44 -07:00
parent 14accf7518
commit 54102ee7d0
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
3 changed files with 19 additions and 9 deletions

View File

@ -36,7 +36,7 @@ pub fn expand_derive_deserialize(
let impl_block = if let Some(remote) = cont.attrs.remote() { let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis; let vis = &input.vis;
let used = pretend::pretend_used(&cont); let used = pretend::pretend_used(&cont, params.is_packed);
quote! { quote! {
impl #de_impl_generics #ident #ty_generics #where_clause { impl #de_impl_generics #ident #ty_generics #where_clause {
#vis fn deserialize<__D>(__deserializer: __D) -> #serde::__private::Result<#remote #ty_generics, __D::Error> #vis fn deserialize<__D>(__deserializer: __D) -> #serde::__private::Result<#remote #ty_generics, __D::Error>
@ -125,6 +125,9 @@ struct Parameters {
/// At least one field has a serde(getter) attribute, implying that the /// At least one field has a serde(getter) attribute, implying that the
/// remote type has a private field. /// remote type has a private field.
has_getter: bool, has_getter: bool,
/// Type has a repr(packed) attribute.
is_packed: bool,
} }
impl Parameters { impl Parameters {
@ -137,6 +140,7 @@ impl Parameters {
let borrowed = borrowed_lifetimes(cont); let borrowed = borrowed_lifetimes(cont);
let generics = build_generics(cont, &borrowed); let generics = build_generics(cont, &borrowed);
let has_getter = cont.data.has_getter(); let has_getter = cont.data.has_getter();
let is_packed = cont.attrs.is_packed();
Parameters { Parameters {
local, local,
@ -144,6 +148,7 @@ impl Parameters {
generics, generics,
borrowed, borrowed,
has_getter, has_getter,
is_packed,
} }
} }

View File

@ -20,8 +20,8 @@ use internals::ast::{Container, Data, Field, Style};
// 8 | enum EnumDef { V } // 8 | enum EnumDef { V }
// | ^ // | ^
// //
pub fn pretend_used(cont: &Container) -> TokenStream { pub fn pretend_used(cont: &Container, is_packed: bool) -> TokenStream {
let pretend_fields = pretend_fields_used(cont); let pretend_fields = pretend_fields_used(cont, is_packed);
let pretend_variants = pretend_variants_used(cont); let pretend_variants = pretend_variants_used(cont);
quote! { quote! {
@ -48,7 +48,7 @@ pub fn pretend_used(cont: &Container) -> TokenStream {
// The `ref` is important in case the user has written a Drop impl on their // The `ref` is important in case the user has written a Drop impl on their
// type. Rust does not allow destructuring a struct or enum that has a Drop // type. Rust does not allow destructuring a struct or enum that has a Drop
// impl. // impl.
fn pretend_fields_used(cont: &Container) -> TokenStream { fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream {
let type_ident = &cont.ident; let type_ident = &cont.ident;
let (_, ty_generics, _) = cont.generics.split_for_impl(); let (_, ty_generics, _) = cont.generics.split_for_impl();
@ -58,14 +58,14 @@ fn pretend_fields_used(cont: &Container) -> TokenStream {
.filter_map(|variant| match variant.style { .filter_map(|variant| match variant.style {
Style::Struct => { Style::Struct => {
let variant_ident = &variant.ident; let variant_ident = &variant.ident;
let pat = struct_pattern(&variant.fields); let pat = struct_pattern(&variant.fields, is_packed);
Some(quote!(#type_ident::#variant_ident #pat)) Some(quote!(#type_ident::#variant_ident #pat))
} }
_ => None, _ => None,
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
Data::Struct(Style::Struct, fields) => { Data::Struct(Style::Struct, fields) => {
let pat = struct_pattern(fields); let pat = struct_pattern(fields, is_packed);
vec![quote!(#type_ident #pat)] vec![quote!(#type_ident #pat)]
} }
Data::Struct(_, _) => { Data::Struct(_, _) => {
@ -132,9 +132,14 @@ fn pretend_variants_used(cont: &Container) -> TokenStream {
quote!(#(#cases)*) quote!(#(#cases)*)
} }
fn struct_pattern(fields: &[Field]) -> TokenStream { fn struct_pattern(fields: &[Field], is_packed: bool) -> TokenStream {
let members = fields.iter().map(|field| &field.member); let members = fields.iter().map(|field| &field.member);
let placeholders = let placeholders =
(0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site())); (0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site()));
quote!({ #(#members: ref #placeholders),* }) let take_reference = if is_packed {
None
} else {
Some(quote!(ref))
};
quote!({ #(#members: #take_reference #placeholders),* })
} }

View File

@ -30,7 +30,7 @@ pub fn expand_derive_serialize(
let impl_block = if let Some(remote) = cont.attrs.remote() { let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis; let vis = &input.vis;
let used = pretend::pretend_used(&cont); let used = pretend::pretend_used(&cont, params.is_packed);
quote! { quote! {
impl #impl_generics #ident #ty_generics #where_clause { impl #impl_generics #ident #ty_generics #where_clause {
#vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error> #vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error>