aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/de.rs56
-rw-r--r--src/lib.rs4
-rw-r--r--src/pretend.rs137
-rw-r--r--src/ser.rs2
4 files changed, 141 insertions, 58 deletions
diff --git a/src/de.rs b/src/de.rs
index 5d0c00f..7f4d7c4 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -36,7 +36,7 @@ pub fn expand_derive_deserialize(
let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis;
- let used = pretend::pretend_used(&cont);
+ let used = pretend::pretend_used(&cont, params.is_packed);
quote! {
impl #de_impl_generics #ident #ty_generics #where_clause {
#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
/// remote type has a private field.
has_getter: bool,
+
+ /// Type has a repr(packed) attribute.
+ is_packed: bool,
}
impl Parameters {
@@ -137,6 +140,7 @@ impl Parameters {
let borrowed = borrowed_lifetimes(cont);
let generics = build_generics(cont, &borrowed);
let has_getter = cont.data.has_getter();
+ let is_packed = cont.attrs.is_packed();
Parameters {
local,
@@ -144,6 +148,7 @@ impl Parameters {
generics,
borrowed,
has_getter,
+ is_packed,
}
}
@@ -1728,6 +1733,8 @@ fn deserialize_externally_tagged_variant(
}
}
+// Generates significant part of the visit_seq and visit_map bodies of visitors
+// for the variants of internally tagged enum.
fn deserialize_internally_tagged_variant(
params: &Parameters,
variant: &Variant,
@@ -1779,11 +1786,9 @@ fn deserialize_untagged_variant(
deserializer: TokenStream,
) -> Fragment {
if let Some(path) = variant.attrs.deserialize_with() {
- let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path);
+ let unwrap_fn = unwrap_to_variant_closure(params, variant, false);
return quote_block! {
- #wrapper
- _serde::__private::Result::map(
- <#wrapper_ty as _serde::Deserialize>::deserialize(#deserializer), #unwrap_fn)
+ _serde::__private::Result::map(#path(#deserializer), #unwrap_fn)
};
}
@@ -2883,44 +2888,61 @@ fn wrap_deserialize_variant_with(
variant: &Variant,
deserialize_with: &syn::ExprPath,
) -> (TokenStream, TokenStream, TokenStream) {
- let this = &params.this;
- let variant_ident = &variant.ident;
-
let field_tys = variant.fields.iter().map(|field| field.ty);
let (wrapper, wrapper_ty) =
wrap_deserialize_with(params, &quote!((#(#field_tys),*)), deserialize_with);
+ let unwrap_fn = unwrap_to_variant_closure(params, variant, true);
+
+ (wrapper, wrapper_ty, unwrap_fn)
+}
+
+// Generates closure that converts single input parameter to the final value.
+fn unwrap_to_variant_closure(
+ params: &Parameters,
+ variant: &Variant,
+ with_wrapper: bool,
+) -> TokenStream {
+ let this = &params.this;
+ let variant_ident = &variant.ident;
+
+ let (arg, wrapper) = if with_wrapper {
+ (quote! { __wrap }, quote! { __wrap.value })
+ } else {
+ let field_tys = variant.fields.iter().map(|field| field.ty);
+ (quote! { __wrap: (#(#field_tys),*) }, quote! { __wrap })
+ };
+
let field_access = (0..variant.fields.len()).map(|n| {
Member::Unnamed(Index {
index: n as u32,
span: Span::call_site(),
})
});
- let unwrap_fn = match variant.style {
+
+ match variant.style {
Style::Struct if variant.fields.len() == 1 => {
let member = &variant.fields[0].member;
quote! {
- |__wrap| #this::#variant_ident { #member: __wrap.value }
+ |#arg| #this::#variant_ident { #member: #wrapper }
}
}
Style::Struct => {
let members = variant.fields.iter().map(|field| &field.member);
quote! {
- |__wrap| #this::#variant_ident { #(#members: __wrap.value.#field_access),* }
+ |#arg| #this::#variant_ident { #(#members: #wrapper.#field_access),* }
}
}
Style::Tuple => quote! {
- |__wrap| #this::#variant_ident(#(__wrap.value.#field_access),*)
+ |#arg| #this::#variant_ident(#(#wrapper.#field_access),*)
},
Style::Newtype => quote! {
- |__wrap| #this::#variant_ident(__wrap.value)
+ |#arg| #this::#variant_ident(#wrapper)
},
Style::Unit => quote! {
- |__wrap| #this::#variant_ident
+ |#arg| #this::#variant_ident
},
- };
-
- (wrapper, wrapper_ty, unwrap_fn)
+ }
}
fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
diff --git a/src/lib.rs b/src/lib.rs
index 7516a90..9bf2c36 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,7 +13,7 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
-#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.127")]
+#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.130")]
#![allow(unknown_lints, bare_trait_objects)]
#![deny(clippy::all, clippy::pedantic)]
// Ignored clippy lints
@@ -21,6 +21,8 @@
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
clippy::branches_sharing_code,
clippy::cognitive_complexity,
+ // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7575
+ clippy::collapsible_match,
clippy::enum_variant_names,
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797
clippy::manual_map,
diff --git a/src/pretend.rs b/src/pretend.rs
index 955ce3d..c4e5874 100644
--- a/src/pretend.rs
+++ b/src/pretend.rs
@@ -1,7 +1,7 @@
-use proc_macro2::{Span, TokenStream};
-use syn::Ident;
+use proc_macro2::TokenStream;
+use quote::format_ident;
-use internals::ast::{Container, Data, Field, Style};
+use internals::ast::{Container, Data, Field, Style, Variant};
// Suppress dead_code warnings that would otherwise appear when using a remote
// derive. Other than this pretend code, a struct annotated with remote derive
@@ -20,8 +20,8 @@ use internals::ast::{Container, Data, Field, Style};
// 8 | enum EnumDef { V }
// | ^
//
-pub fn pretend_used(cont: &Container) -> TokenStream {
- let pretend_fields = pretend_fields_used(cont);
+pub fn pretend_used(cont: &Container, is_packed: bool) -> TokenStream {
+ let pretend_fields = pretend_fields_used(cont, is_packed);
let pretend_variants = pretend_variants_used(cont);
quote! {
@@ -32,49 +32,115 @@ pub fn pretend_used(cont: &Container) -> TokenStream {
// For structs with named fields, expands to:
//
+// match None::<&T> {
+// Some(T { a: __v0, b: __v1 }) => {}
+// _ => {}
+// }
+//
+// For packed structs on sufficiently new rustc, expands to:
+//
+// match None::<&T> {
+// Some(__v @ T { a: _, b: _ }) => {
+// let _ = addr_of!(__v.a);
+// let _ = addr_of!(__v.b);
+// }
+// _ => {}
+// }
+//
+// For packed structs on older rustc, we assume Sized and !Drop, and expand to:
+//
// match None::<T> {
-// Some(T { a: ref __v0, b: ref __v1 }) => {}
+// Some(T { a: __v0, b: __v1 }) => {}
// _ => {}
// }
//
// For enums, expands to the following but only including struct variants:
//
-// match None::<T> {
-// Some(T::A { a: ref __v0 }) => {}
-// Some(T::B { b: ref __v0 }) => {}
+// match None::<&T> {
+// Some(T::A { a: __v0 }) => {}
+// Some(T::B { b: __v0 }) => {}
// _ => {}
// }
//
-// 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
-// impl.
-fn pretend_fields_used(cont: &Container) -> TokenStream {
+fn pretend_fields_used(cont: &Container, is_packed: bool) -> TokenStream {
+ match &cont.data {
+ Data::Enum(variants) => pretend_fields_used_enum(cont, variants),
+ Data::Struct(Style::Struct, fields) => if is_packed {
+ pretend_fields_used_struct_packed(cont, fields)
+ } else {
+ pretend_fields_used_struct(cont, fields)
+ },
+ Data::Struct(_, _) => quote!(),
+ }
+}
+
+fn pretend_fields_used_struct(cont: &Container, fields: &[Field]) -> TokenStream {
let type_ident = &cont.ident;
let (_, ty_generics, _) = cont.generics.split_for_impl();
- let patterns = match &cont.data {
- Data::Enum(variants) => variants
- .iter()
- .filter_map(|variant| match variant.style {
- Style::Struct => {
- let variant_ident = &variant.ident;
- let pat = struct_pattern(&variant.fields);
- Some(quote!(#type_ident::#variant_ident #pat))
+ let members = fields.iter().map(|field| &field.member);
+ let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
+
+ quote! {
+ match _serde::__private::None::<&#type_ident #ty_generics> {
+ _serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
+ _ => {}
+ }
+ }
+}
+
+fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> TokenStream {
+ let type_ident = &cont.ident;
+ let (_, ty_generics, _) = cont.generics.split_for_impl();
+
+ let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
+
+ #[cfg(ptr_addr_of)]
+ {
+ quote! {
+ match _serde::__private::None::<&#type_ident #ty_generics> {
+ _serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
+ #(
+ let _ = _serde::__private::ptr::addr_of!(__v.#members);
+ )*
}
- _ => None,
- })
- .collect::<Vec<_>>(),
- Data::Struct(Style::Struct, fields) => {
- let pat = struct_pattern(fields);
- vec![quote!(#type_ident #pat)]
+ _ => {}
+ }
}
- Data::Struct(_, _) => {
- return quote!();
+ }
+
+ #[cfg(not(ptr_addr_of))]
+ {
+ let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
+
+ quote! {
+ match _serde::__private::None::<#type_ident #ty_generics> {
+ _serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
+ _ => {}
+ }
}
- };
+ }
+}
+
+fn pretend_fields_used_enum(cont: &Container, variants: &[Variant]) -> TokenStream {
+ let type_ident = &cont.ident;
+ let (_, ty_generics, _) = cont.generics.split_for_impl();
+
+ let patterns = variants
+ .iter()
+ .filter_map(|variant| match variant.style {
+ Style::Struct => {
+ let variant_ident = &variant.ident;
+ let members = variant.fields.iter().map(|field| &field.member);
+ let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
+ Some(quote!(#type_ident::#variant_ident { #(#members: #placeholders),* }))
+ }
+ _ => None,
+ })
+ .collect::<Vec<_>>();
quote! {
- match _serde::__private::None::<#type_ident #ty_generics> {
+ match _serde::__private::None::<&#type_ident #ty_generics> {
#(
_serde::__private::Some(#patterns) => {}
)*
@@ -107,7 +173,7 @@ fn pretend_variants_used(cont: &Container) -> TokenStream {
let cases = variants.iter().map(|variant| {
let variant_ident = &variant.ident;
let placeholders = &(0..variant.fields.len())
- .map(|i| Ident::new(&format!("__v{}", i), Span::call_site()))
+ .map(|i| format_ident!("__v{}", i))
.collect::<Vec<_>>();
let pat = match variant.style {
@@ -131,10 +197,3 @@ fn pretend_variants_used(cont: &Container) -> TokenStream {
quote!(#(#cases)*)
}
-
-fn struct_pattern(fields: &[Field]) -> TokenStream {
- let members = fields.iter().map(|field| &field.member);
- let placeholders =
- (0..fields.len()).map(|i| Ident::new(&format!("__v{}", i), Span::call_site()));
- quote!({ #(#members: ref #placeholders),* })
-}
diff --git a/src/ser.rs b/src/ser.rs
index 4f3e5ff..529a20d 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -30,7 +30,7 @@ pub fn expand_derive_serialize(
let impl_block = if let Some(remote) = cont.attrs.remote() {
let vis = &input.vis;
- let used = pretend::pretend_used(&cont);
+ let used = pretend::pretend_used(&cont, params.is_packed);
quote! {
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>