diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-10 06:58:06 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-05-10 06:58:06 +0000 |
commit | fe550d782c1dcc87676c5590ef684b329e22d0fa (patch) | |
tree | 91380375cadc4e0835f7e031ac39e9a33dce2c13 | |
parent | 92ed66199eb5b1ef475b309262864e86071a3773 (diff) | |
parent | 6e1d8718fc5e3dbc97a6b030204ef46f4e0289dd (diff) | |
download | serde_derive-android13-mainline-cellbroadcast-release.tar.gz |
Snap for 8564071 from 6e1d8718fc5e3dbc97a6b030204ef46f4e0289dd to mainline-cellbroadcast-releaseaml_cbr_331910000aml_cbr_331810000aml_cbr_331710020aml_cbr_331610010aml_cbr_331510000aml_cbr_331411000aml_cbr_331310010aml_cbr_331111030aml_cbr_331013010aml_cbr_330911010aml_cbr_330810000android13-mainline-cellbroadcast-release
Change-Id: Id11e2ec824bf0cd37f49ddf3cc9af20e5f86abc7
-rw-r--r-- | .cargo_vcs_info.json | 7 | ||||
-rw-r--r-- | Android.bp | 16 | ||||
-rw-r--r-- | Cargo.toml | 12 | ||||
-rw-r--r-- | Cargo.toml.orig | 3 | ||||
-rw-r--r-- | METADATA | 10 | ||||
-rw-r--r-- | README.md | 23 | ||||
-rw-r--r-- | TEST_MAPPING | 109 | ||||
-rw-r--r-- | build.rs | 6 | ||||
-rw-r--r-- | cargo2android.json | 4 | ||||
-rw-r--r-- | crates-io.md | 23 | ||||
-rw-r--r-- | src/bound.rs | 8 | ||||
-rw-r--r-- | src/de.rs | 70 | ||||
-rw-r--r-- | src/dummy.rs | 2 | ||||
-rw-r--r-- | src/internals/ast.rs | 2 | ||||
-rw-r--r-- | src/internals/attr.rs | 8 | ||||
-rw-r--r-- | src/internals/check.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 14 | ||||
-rw-r--r-- | src/pretend.rs | 139 | ||||
-rw-r--r-- | src/ser.rs | 4 |
19 files changed, 337 insertions, 127 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 71f38ef..7239a8b 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,6 @@ { "git": { - "sha1": "3d6c4149b177e9cadfb948ebc6d1e55b33861792" - } -} + "sha1": "02bd79a0bada78dd88d050f6478806f001f41fb0" + }, + "path_in_vcs": "serde_derive" +}
\ No newline at end of file @@ -1,4 +1,5 @@ -// This file is generated by cargo2android.py --run --device --dependencies. +// This file is generated by cargo2android.py --config cargo2android.json. +// Do not modify this file as changes will be overridden on upgrade. package { default_applicable_licenses: ["external_rust_crates_serde_derive_license"], @@ -39,11 +40,14 @@ license { rust_proc_macro { name: "libserde_derive", crate_name: "serde_derive", + cargo_env_compat: true, + cargo_pkg_version: "1.0.136", srcs: ["src/lib.rs"], edition: "2015", features: ["default"], - flags: [ - "--cfg underscore_consts", + cfgs: [ + "ptr_addr_of", + "underscore_consts", ], rustlibs: [ "libproc_macro2", @@ -51,9 +55,3 @@ rust_proc_macro { "libsyn", ], } - -// dependent_library ["feature_list"] -// proc-macro2-1.0.24 "default,proc-macro" -// quote-1.0.8 "default,proc-macro" -// syn-1.0.60 "clone-impls,default,derive,parsing,printing,proc-macro,quote" -// unicode-xid-0.2.1 "default" @@ -3,16 +3,16 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] +rust-version = "1.31" name = "serde_derive" -version = "1.0.123" +version = "1.0.136" authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 24e2f6b..47fda7f 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,7 +1,8 @@ [package] name = "serde_derive" -version = "1.0.123" # remember to update html_root_url +version = "1.0.136" # remember to update html_root_url authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] +rust-version = "1.31" license = "MIT OR Apache-2.0" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" homepage = "https://serde.rs" @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/serde_derive/serde_derive-1.0.123.crate" + value: "https://static.crates.io/crates/serde_derive/serde_derive-1.0.136.crate" } - version: "1.0.123" + version: "1.0.136" license_type: NOTICE last_upgrade_date { - year: 2021 - month: 2 - day: 9 + year: 2022 + month: 3 + day: 1 } } @@ -77,17 +77,20 @@ fn main() { Serde is one of the most widely used Rust libraries so any place that Rustaceans congregate will be able to help you out. For chat, consider trying the -[#general] or [#beginners] channels of the unofficial community Discord, the -[#rust-usage] channel of the official Rust Project Discord, or the -[#general][zulip] stream in Zulip. For asynchronous, consider the [\[rust\] tag -on StackOverflow][stackoverflow], the [/r/rust] subreddit which has a pinned -weekly easy questions post, or the Rust [Discourse forum][discourse]. It's -acceptable to file a support issue in this repo but they tend not to get as many -eyes as any of the above and may get closed without a response after some time. - -[#general]: https://discord.com/channels/273534239310479360/274215136414400513 -[#beginners]: https://discord.com/channels/273534239310479360/273541522815713281 +[#rust-questions] or [#rust-beginners] channels of the unofficial community +Discord (invite: <https://discord.gg/rust-lang-community>), the [#rust-usage] or +[#beginners] channels of the official Rust Project Discord (invite: +<https://discord.gg/rust-lang>), or the [#general][zulip] stream in Zulip. For +asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the +[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust +[Discourse forum][discourse]. It's acceptable to file a support issue in this +repo but they tend not to get as many eyes as any of the above and may get +closed without a response after some time. + +[#rust-questions]: https://discord.com/channels/273534239310479360/274215136414400513 +[#rust-beginners]: https://discord.com/channels/273534239310479360/273541522815713281 [#rust-usage]: https://discord.com/channels/442252698964721669/443150878111694848 +[#beginners]: https://discord.com/channels/442252698964721669/448238009733742612 [zulip]: https://rust-lang.zulipchat.com/#narrow/stream/122651-general [stackoverflow]: https://stackoverflow.com/questions/tagged/rust [/r/rust]: https://www.reddit.com/r/rust diff --git a/TEST_MAPPING b/TEST_MAPPING index f4547bb..b424c9c 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -1,14 +1,117 @@ // Generated by update_crate_tests.py for tests that depend on this crate. { + "imports": [ + { + "path": "external/rust/crates/base64" + }, + { + "path": "external/rust/crates/bitflags" + }, + { + "path": "external/rust/crates/bytes" + }, + { + "path": "external/rust/crates/either" + }, + { + "path": "external/rust/crates/rand_chacha" + }, + { + "path": "external/rust/crates/serde" + }, + { + "path": "external/rust/crates/serde-xml-rs" + }, + { + "path": "external/rust/crates/serde_cbor" + }, + { + "path": "external/rust/crates/slab" + }, + { + "path": "external/rust/crates/tinytemplate" + }, + { + "path": "external/rust/crates/tinyvec" + }, + { + "path": "external/rust/crates/unicode-bidi" + }, + { + "path": "external/rust/crates/unicode-xid" + }, + { + "path": "external/rust/crates/url" + } + ], "presubmit": [ { - "name": "url_device_test_src_lib" + "name": "ZipFuseTest" + }, + { + "name": "apkdmverity.test" + }, + { + "name": "authfs_device_test_src_lib" + }, + { + "name": "diced_test" + }, + { + "name": "diced_vendor_test" + }, + { + "name": "keystore2_test" + }, + { + "name": "keystore2_test_utils_test" + }, + { + "name": "legacykeystore_test" + }, + { + "name": "libcert_request_validator_tests" + }, + { + "name": "microdroid_manager_test" + }, + { + "name": "virtualizationservice_device_test" + } + ], + "presubmit-rust": [ + { + "name": "ZipFuseTest" + }, + { + "name": "apkdmverity.test" + }, + { + "name": "authfs_device_test_src_lib" + }, + { + "name": "diced_test" + }, + { + "name": "diced_vendor_test" + }, + { + "name": "keystore2_test" + }, + { + "name": "keystore2_test_utils_test" + }, + { + "name": "legacykeystore_test" + }, + { + "name": "libcert_request_validator_tests" }, { - "name": "unicode-bidi_device_test_src_lib" + "name": "microdroid_manager_test" }, { - "name": "serde_test_device_test_src_lib" + "name": "virtualizationservice_device_test" } ] } @@ -16,6 +16,12 @@ fn main() { if minor >= 37 { println!("cargo:rustc-cfg=underscore_consts"); } + + // The ptr::addr_of! macro stabilized in Rust 1.51: + // https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis + if minor >= 51 { + println!("cargo:rustc-cfg=ptr_addr_of"); + } } fn rustc_minor_version() -> Option<u32> { diff --git a/cargo2android.json b/cargo2android.json new file mode 100644 index 0000000..bf78496 --- /dev/null +++ b/cargo2android.json @@ -0,0 +1,4 @@ +{ + "device": true, + "run": true +}
\ No newline at end of file diff --git a/crates-io.md b/crates-io.md index 0775761..b57bc5f 100644 --- a/crates-io.md +++ b/crates-io.md @@ -45,17 +45,20 @@ fn main() { Serde is one of the most widely used Rust libraries so any place that Rustaceans congregate will be able to help you out. For chat, consider trying the -[#general] or [#beginners] channels of the unofficial community Discord, the -[#rust-usage] channel of the official Rust Project Discord, or the -[#general][zulip] stream in Zulip. For asynchronous, consider the [\[rust\] tag -on StackOverflow][stackoverflow], the [/r/rust] subreddit which has a pinned -weekly easy questions post, or the Rust [Discourse forum][discourse]. It's -acceptable to file a support issue in this repo but they tend not to get as many -eyes as any of the above and may get closed without a response after some time. - -[#general]: https://discord.com/channels/273534239310479360/274215136414400513 -[#beginners]: https://discord.com/channels/273534239310479360/273541522815713281 +[#rust-questions] or [#rust-beginners] channels of the unofficial community +Discord (invite: <https://discord.gg/rust-lang-community>, the [#rust-usage] or +[#beginners] channels of the official Rust Project Discord (invite: +<https://discord.gg/rust-lang>), or the [#general][zulip] stream in Zulip. For +asynchronous, consider the [\[rust\] tag on StackOverflow][stackoverflow], the +[/r/rust] subreddit which has a pinned weekly easy questions post, or the Rust +[Discourse forum][discourse]. It's acceptable to file a support issue in this +repo but they tend not to get as many eyes as any of the above and may get +closed without a response after some time. + +[#rust-questions]: https://discord.com/channels/273534239310479360/274215136414400513 +[#rust-beginners]: https://discord.com/channels/273534239310479360/273541522815713281 [#rust-usage]: https://discord.com/channels/442252698964721669/443150878111694848 +[#beginners]: https://discord.com/channels/442252698964721669/448238009733742612 [zulip]: https://rust-lang.zulipchat.com/#narrow/stream/122651-general [stackoverflow]: https://stackoverflow.com/questions/tagged/rust [/r/rust]: https://www.reddit.com/r/rust diff --git a/src/bound.rs b/src/bound.rs index 0949dfc..abca467 100644 --- a/src/bound.rs +++ b/src/bound.rs @@ -49,8 +49,8 @@ pub fn with_where_predicates_from_fields( let predicates = cont .data .all_fields() - .flat_map(|field| from_field(&field.attrs)) - .flat_map(|predicates| predicates.to_vec()); + .filter_map(|field| from_field(&field.attrs)) + .flat_map(<[syn::WherePredicate]>::to_vec); let mut generics = generics.clone(); generics.make_where_clause().predicates.extend(predicates); @@ -71,8 +71,8 @@ pub fn with_where_predicates_from_variants( let predicates = variants .iter() - .flat_map(|variant| from_variant(&variant.attrs)) - .flat_map(|predicates| predicates.to_vec()); + .filter_map(|variant| from_variant(&variant.attrs)) + .flat_map(<[syn::WherePredicate]>::to_vec); let mut generics = generics.clone(); generics.make_where_clause().predicates.extend(predicates); @@ -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, } } @@ -475,7 +480,7 @@ fn deserialize_tuple( }; let visit_seq = Stmts(deserialize_seq( - &type_path, params, fields, false, cattrs, &expecting, + &type_path, params, fields, false, cattrs, expecting, )); let visitor_expr = quote! { @@ -561,7 +566,7 @@ fn deserialize_tuple_in_place( None }; - let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting)); + let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting)); let visitor_expr = quote! { __Visitor { @@ -922,7 +927,7 @@ fn deserialize_struct( let expecting = cattrs.expecting().unwrap_or(&expecting); let visit_seq = Stmts(deserialize_seq( - &type_path, params, fields, true, cattrs, &expecting, + &type_path, params, fields, true, cattrs, expecting, )); let (field_visitor, fields_stmt, visit_map) = if cattrs.has_flatten() { @@ -1063,7 +1068,7 @@ fn deserialize_struct_in_place( }; let expecting = cattrs.expecting().unwrap_or(&expecting); - let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, &expecting)); + let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting)); let (field_visitor, fields_stmt, visit_map) = deserialize_struct_as_struct_in_place_visitor(params, fields, cattrs); @@ -1453,7 +1458,7 @@ fn deserialize_adjacently_tagged_enum( while let _serde::__private::Some(__k) = #next_key { match __k { _serde::__private::de::TagContentOtherField::Other => { - try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)); + let _ = try!(_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)); continue; }, _serde::__private::de::TagContentOtherField::Tag => { @@ -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) }; } @@ -2087,7 +2092,7 @@ fn deserialize_identifier( ) -> Fragment { let mut flat_fields = Vec::new(); for (_, ident, aliases) in fields { - flat_fields.extend(aliases.iter().map(|alias| (alias, ident))) + flat_fields.extend(aliases.iter().map(|alias| (alias, ident))); } let field_strs: &Vec<_> = &flat_fields.iter().map(|(name, _)| name).collect(); @@ -2285,7 +2290,7 @@ fn deserialize_identifier( }; let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields { - let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(&fallthrough_arm); + let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(fallthrough_arm); Some(quote! { fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result<Self::Value, __E> where @@ -2883,44 +2888,61 @@ fn wrap_deserialize_variant_with( variant: &Variant, deserialize_with: &syn::ExprPath, ) -> (TokenStream, TokenStream, TokenStream) { - let this = ¶ms.this; - let variant_ident = &variant.ident; - let field_tys = variant.fields.iter().map(|field| field.ty); let (wrapper, wrapper_ty) = wrap_deserialize_with(params, "e!((#(#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 = ¶ms.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/dummy.rs b/src/dummy.rs index 9a4e5f0..29de260 100644 --- a/src/dummy.rs +++ b/src/dummy.rs @@ -23,7 +23,7 @@ pub fn wrap_in_const( use #path as _serde; }, None => quote! { - #[allow(rust_2018_idioms, clippy::useless_attribute)] + #[allow(unused_extern_crates, clippy::useless_attribute)] extern crate serde as _serde; }, }; diff --git a/src/internals/ast.rs b/src/internals/ast.rs index 1afdaee..2a6950b 100644 --- a/src/internals/ast.rs +++ b/src/internals/ast.rs @@ -23,7 +23,7 @@ pub struct Container<'a> { /// The fields of a struct or enum. /// -/// Analagous to `syn::Data`. +/// Analogous to `syn::Data`. pub enum Data<'a> { Enum(Vec<Variant<'a>>), Struct(Style, Vec<Field<'a>>), diff --git a/src/internals/attr.rs b/src/internals/attr.rs index dcc4bf8..13f5525 100644 --- a/src/internals/attr.rs +++ b/src/internals/attr.rs @@ -556,7 +556,7 @@ impl Container { // Parse `#[serde(crate = "foo")]` Meta(NameValue(m)) if m.path == CRATE => { if let Ok(path) = parse_lit_into_path(cx, CRATE, &m.lit) { - serde_path.set(&m.path, path) + serde_path.set(&m.path, path); } } @@ -1609,7 +1609,7 @@ fn get_lit_str2<'a>( fn parse_lit_into_path(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result<syn::Path, ()> { let string = get_lit_str(cx, attr_name, lit)?; parse_lit_str(string).map_err(|_| { - cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value())) + cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value())); }) } @@ -1620,7 +1620,7 @@ fn parse_lit_into_expr_path( ) -> Result<syn::ExprPath, ()> { let string = get_lit_str(cx, attr_name, lit)?; parse_lit_str(string).map_err(|_| { - cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value())) + cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value())); }) } @@ -1649,7 +1649,7 @@ fn parse_lit_into_ty(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result<syn cx.error_spanned_by( lit, format!("failed to parse type: {} = {:?}", attr_name, string.value()), - ) + ); }) } diff --git a/src/internals/check.rs b/src/internals/check.rs index 30ede1c..0e2484a 100644 --- a/src/internals/check.rs +++ b/src/internals/check.rs @@ -260,7 +260,7 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { cx.error_spanned_by( cont.original, format!("variant field name `{}` conflicts with internal tag", tag), - ) + ); }; for variant in variants { @@ -396,7 +396,7 @@ fn member_message(member: &Member) -> String { } fn allow_transparent(field: &Field, derive: Derive) -> bool { - if let Type::Path(ty) = ungroup(&field.ty) { + if let Type::Path(ty) = ungroup(field.ty) { if let Some(seg) = ty.path.segments.last() { if seg.ident == "PhantomData" { return false; @@ -13,13 +13,18 @@ //! //! [https://serde.rs/derive.html]: https://serde.rs/derive.html -#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.123")] +#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.136")] #![allow(unknown_lints, bare_trait_objects)] -#![deny(clippy::all, clippy::pedantic)] // Ignored clippy lints #![allow( + // 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, clippy::match_like_matches_macro, clippy::needless_pass_by_value, clippy::too_many_arguments, @@ -35,11 +40,14 @@ clippy::checked_conversions, clippy::doc_markdown, clippy::enum_glob_use, - clippy::filter_map, clippy::indexing_slicing, clippy::items_after_statements, + clippy::let_underscore_drop, + clippy::manual_assert, clippy::map_err_ignore, clippy::match_same_arms, + // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984 + clippy::match_wildcard_for_single_variants, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::option_if_let_else, diff --git a/src/pretend.rs b/src/pretend.rs index 955ce3d..3af6a66 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,117 @@ 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 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 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).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 +175,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 +199,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),* }) -} @@ -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> @@ -1099,7 +1099,7 @@ fn serialize_struct_visitor( let mut field_expr = if is_enum { quote!(#member) } else { - get_member(params, field, &member) + get_member(params, field, member) }; let key_expr = field.attrs.name().serialize_name(); |