aboutsummaryrefslogtreecommitdiff
path: root/src/pretend.rs
diff options
context:
space:
mode:
authorJoel Galenson <jgalenson@google.com>2021-09-22 11:19:44 -0700
committerJoel Galenson <jgalenson@google.com>2021-09-22 11:19:44 -0700
commit0efbd40678185898855d20949f214d7c55e075ba (patch)
tree9767e8ee4aefab4b6992d8cbc27f9ac98220a93f /src/pretend.rs
parentb3ad500f0e2eb2022859078339a8b2b4bb42332f (diff)
downloadserde_derive-0efbd40678185898855d20949f214d7c55e075ba.tar.gz
Upgrade rust/crates/serde_derive to 1.0.130
Test: make Change-Id: I2357003e23ca7a9582ebc171da5673f3e2be9a0d
Diffstat (limited to 'src/pretend.rs')
-rw-r--r--src/pretend.rs137
1 files changed, 98 insertions, 39 deletions
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),* })
-}