From 0421e426a36fdc8d8c4e6d939241b7611664e0f4 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Mon, 20 Mar 2023 22:48:56 +0000 Subject: Upgrade serde_derive to 1.0.158 This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update rust/crates/serde_derive For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md Test: TreeHugger Bug: 276463929 Change-Id: I7d14b675c82d5d22d6ea435fa2d6ccb270e3d323 --- .cargo_vcs_info.json | 2 +- Android.bp | 4 +- Cargo.toml | 6 +- Cargo.toml.orig | 6 +- LICENSE-APACHE | 25 - METADATA | 8 +- README.md | 10 +- src/bound.rs | 18 +- src/de.rs | 36 +- src/dummy.rs | 6 +- src/internals/attr.rs | 1280 ++++++++++++++++++++------------------------- src/internals/check.rs | 63 ++- src/internals/receiver.rs | 17 +- src/internals/symbol.rs | 3 +- src/lib.rs | 3 +- 15 files changed, 652 insertions(+), 835 deletions(-) diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index d6b3c53..7978e02 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "ccf9c6fc072378ea8c4f15df1024e258d35d6e61" + "sha1": "e3058105f0b1a64018577b12ea19cd255644a17b" }, "path_in_vcs": "serde_derive" } \ No newline at end of file diff --git a/Android.bp b/Android.bp index 1c23ba9..125c57a 100644 --- a/Android.bp +++ b/Android.bp @@ -41,7 +41,7 @@ rust_proc_macro { name: "libserde_derive", crate_name: "serde_derive", cargo_env_compat: true, - cargo_pkg_version: "1.0.152", + cargo_pkg_version: "1.0.158", srcs: ["src/lib.rs"], edition: "2015", features: ["default"], @@ -59,7 +59,7 @@ rust_test_host { name: "serde_derive_test_src_lib", crate_name: "serde_derive", cargo_env_compat: true, - cargo_pkg_version: "1.0.152", + cargo_pkg_version: "1.0.158", srcs: ["src/lib.rs"], test_suites: ["general-tests"], auto_gen_config: true, diff --git a/Cargo.toml b/Cargo.toml index 6258d9d..2b9e4df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,9 @@ # See Cargo.toml.orig for the original contents. [package] -rust-version = "1.31" +rust-version = "1.56" name = "serde_derive" -version = "1.0.152" +version = "1.0.158" authors = [ "Erick Tryzelaar ", "David Tolnay ", @@ -53,7 +53,7 @@ version = "1.0" version = "1.0" [dependencies.syn] -version = "1.0.104" +version = "2.0.3" [dev-dependencies.serde] version = "1.0" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index e1366f1..1a3490a 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "serde_derive" -version = "1.0.152" # remember to update html_root_url +version = "1.0.158" # remember to update html_root_url authors = ["Erick Tryzelaar ", "David Tolnay "] categories = ["no-std"] description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" @@ -11,7 +11,7 @@ keywords = ["serde", "serialization", "no_std", "derive"] license = "MIT OR Apache-2.0" readme = "crates-io.md" repository = "https://github.com/serde-rs/serde" -rust-version = "1.31" +rust-version = "1.56" [features] default = [] @@ -24,7 +24,7 @@ proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" -syn = "1.0.104" +syn = "2.0.3" [dev-dependencies] serde = { version = "1.0", path = "../serde" } diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 16fe87b..1b5ec8b 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/METADATA b/METADATA index a9fa596..cc6c728 100644 --- a/METADATA +++ b/METADATA @@ -11,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/serde_derive/serde_derive-1.0.152.crate" + value: "https://static.crates.io/crates/serde_derive/serde_derive-1.0.158.crate" } - version: "1.0.152" + version: "1.0.158" license_type: NOTICE last_upgrade_date { year: 2023 - month: 2 - day: 6 + month: 3 + day: 20 } } diff --git a/README.md b/README.md index c3f6575..d53e572 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -# Serde   [![Build Status]][actions] [![Latest Version]][crates.io] [![serde: rustc 1.13+]][Rust 1.13] [![serde_derive: rustc 1.31+]][Rust 1.31] +# Serde   [![Build Status]][actions] [![Latest Version]][crates.io] [![serde: rustc 1.19+]][Rust 1.19] [![serde_derive: rustc 1.56+]][Rust 1.56] [Build Status]: https://img.shields.io/github/actions/workflow/status/serde-rs/serde/ci.yml?branch=master [actions]: https://github.com/serde-rs/serde/actions?query=branch%3Amaster [Latest Version]: https://img.shields.io/crates/v/serde.svg [crates.io]: https://crates.io/crates/serde -[serde: rustc 1.13+]: https://img.shields.io/badge/serde-rustc_1.13+-lightgray.svg -[serde_derive: rustc 1.31+]: https://img.shields.io/badge/serde_derive-rustc_1.31+-lightgray.svg -[Rust 1.13]: https://blog.rust-lang.org/2016/11/10/Rust-1.13.html -[Rust 1.31]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html +[serde: rustc 1.19+]: https://img.shields.io/badge/serde-rustc_1.19+-lightgray.svg +[serde_derive: rustc 1.56+]: https://img.shields.io/badge/serde_derive-rustc_1.56+-lightgray.svg +[Rust 1.19]: https://blog.rust-lang.org/2017/07/20/Rust-1.19.html +[Rust 1.56]: https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html **Serde is a framework for *ser*ializing and *de*serializing Rust data structures efficiently and generically.** diff --git a/src/bound.rs b/src/bound.rs index 74c9506..7bdb046 100644 --- a/src/bound.rs +++ b/src/bound.rs @@ -200,10 +200,16 @@ pub fn with_bound( for arg in &arguments.args { match arg { syn::GenericArgument::Type(arg) => self.visit_type(arg), - syn::GenericArgument::Binding(arg) => self.visit_type(&arg.ty), + syn::GenericArgument::AssocType(arg) => self.visit_type(&arg.ty), syn::GenericArgument::Lifetime(_) - | syn::GenericArgument::Constraint(_) - | syn::GenericArgument::Const(_) => {} + | syn::GenericArgument::Const(_) + | syn::GenericArgument::AssocConst(_) + | syn::GenericArgument::Constraint(_) => {} + #[cfg_attr( + all(test, exhaustive), + deny(non_exhaustive_omitted_patterns) + )] + _ => {} } } } @@ -226,7 +232,9 @@ pub fn with_bound( fn visit_type_param_bound(&mut self, bound: &'ast syn::TypeParamBound) { match bound { syn::TypeParamBound::Trait(bound) => self.visit_path(&bound.path), - syn::TypeParamBound::Lifetime(_) => {} + syn::TypeParamBound::Lifetime(_) | syn::TypeParamBound::Verbatim(_) => {} + #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + _ => {} } } @@ -334,7 +342,7 @@ pub fn with_self_bound( pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics { let bound = syn::Lifetime::new(lifetime, Span::call_site()); - let def = syn::LifetimeDef { + let def = syn::LifetimeParam { attrs: Vec::new(), lifetime: bound.clone(), colon_token: None, diff --git a/src/de.rs b/src/de.rs index a703ada..d4238f1 100644 --- a/src/de.rs +++ b/src/de.rs @@ -244,9 +244,9 @@ impl BorrowedLifetimes { } } - fn de_lifetime_def(&self) -> Option { + fn de_lifetime_param(&self) -> Option { match self { - BorrowedLifetimes::Borrowed(bounds) => Some(syn::LifetimeDef { + BorrowedLifetimes::Borrowed(bounds) => Some(syn::LifetimeParam { attrs: Vec::new(), lifetime: syn::Lifetime::new("'de", Span::call_site()), colon_token: None, @@ -954,6 +954,7 @@ fn deserialize_struct( lifetime: _serde::__private::PhantomData, } }; + let need_seed = deserializer.is_none(); let dispatch = if let Some(deserializer) = deserializer { quote! { _serde::Deserializer::deserialize_any(#deserializer, #visitor_expr) @@ -999,14 +1000,14 @@ fn deserialize_struct( _ => None, }; - let visitor_seed = if is_enum && cattrs.has_flatten() { + let visitor_seed = if need_seed && is_enum && cattrs.has_flatten() { Some(quote! { impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause { type Value = #this_type #ty_generics; fn deserialize<__D>(self, __deserializer: __D) -> _serde::__private::Result where - __D: _serde::Deserializer<'de>, + __D: _serde::Deserializer<#delife>, { _serde::Deserializer::deserialize_map(__deserializer, self) } @@ -1256,7 +1257,7 @@ fn deserialize_externally_tagged_enum( // This is an empty enum like `enum Impossible {}` or an enum in which // all variants have `#[serde(skip_deserializing)]`. quote! { - // FIXME: Once we drop support for Rust 1.15: + // FIXME: Once feature(exhaustive_patterns) is stable: // let _serde::__private::Err(__err) = _serde::de::EnumAccess::variant::<__Field>(__data); // _serde::__private::Err(__err) _serde::__private::Result::map( @@ -2400,7 +2401,10 @@ fn deserialize_struct_as_struct_visitor( .collect(); let fields_stmt = { - let field_names = field_names_idents.iter().map(|(name, _, _)| name); + let field_names = field_names_idents + .iter() + .flat_map(|(_, _, aliases)| aliases); + quote_block! { const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; } @@ -2535,7 +2539,7 @@ fn deserialize_map( let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); let match_keys = if cattrs.deny_unknown_fields() && all_skipped { quote! { - // FIXME: Once we drop support for Rust 1.15: + // FIXME: Once feature(exhaustive_patterns) is stable: // let _serde::__private::None::<__Field> = try!(_serde::de::MapAccess::next_key(&mut __map)); _serde::__private::Option::map( try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)), @@ -2768,7 +2772,7 @@ fn deserialize_map_in_place( let match_keys = if cattrs.deny_unknown_fields() && all_skipped { quote! { - // FIXME: Once we drop support for Rust 1.15: + // FIXME: Once feature(exhaustive_patterns) is stable: // let _serde::__private::None::<__Field> = try!(_serde::de::MapAccess::next_key(&mut __map)); _serde::__private::Option::map( try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map)), @@ -3007,7 +3011,7 @@ struct InPlaceImplGenerics<'a>(&'a Parameters); impl<'a> ToTokens for DeImplGenerics<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { let mut generics = self.0.generics.clone(); - if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() { + if let Some(de_lifetime) = self.0.borrowed.de_lifetime_param() { generics.params = Some(syn::GenericParam::Lifetime(de_lifetime)) .into_iter() .chain(generics.params) @@ -3042,7 +3046,7 @@ impl<'a> ToTokens for InPlaceImplGenerics<'a> { .into_iter() .chain(generics.params) .collect(); - if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() { + if let Some(de_lifetime) = self.0.borrowed.de_lifetime_param() { generics.params = Some(syn::GenericParam::Lifetime(de_lifetime)) .into_iter() .chain(generics.params) @@ -3067,8 +3071,8 @@ struct InPlaceTypeGenerics<'a>(&'a Parameters); impl<'a> ToTokens for DeTypeGenerics<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { let mut generics = self.0.generics.clone(); - if self.0.borrowed.de_lifetime_def().is_some() { - let def = syn::LifetimeDef { + if self.0.borrowed.de_lifetime_param().is_some() { + let def = syn::LifetimeParam { attrs: Vec::new(), lifetime: syn::Lifetime::new("'de", Span::call_site()), colon_token: None, @@ -3093,8 +3097,8 @@ impl<'a> ToTokens for InPlaceTypeGenerics<'a> { .chain(generics.params) .collect(); - if self.0.borrowed.de_lifetime_def().is_some() { - let def = syn::LifetimeDef { + if self.0.borrowed.de_lifetime_param().is_some() { + let def = syn::LifetimeParam { attrs: Vec::new(), lifetime: syn::Lifetime::new("'de", Span::call_site()), colon_token: None, @@ -3118,8 +3122,8 @@ impl<'a> DeTypeGenerics<'a> { } #[cfg(feature = "deserialize_in_place")] -fn place_lifetime() -> syn::LifetimeDef { - syn::LifetimeDef { +fn place_lifetime() -> syn::LifetimeParam { + syn::LifetimeParam { attrs: Vec::new(), lifetime: syn::Lifetime::new("'place", Span::call_site()), colon_token: None, diff --git a/src/dummy.rs b/src/dummy.rs index a02bd37..2be5027 100644 --- a/src/dummy.rs +++ b/src/dummy.rs @@ -39,10 +39,6 @@ pub fn wrap_in_const( } } -#[allow(deprecated)] fn unraw(ident: &Ident) -> String { - // str::trim_start_matches was added in 1.30, trim_left_matches deprecated - // in 1.33. We currently support rustc back to 1.15 so we need to continue - // to use the deprecated one. - ident.to_string().trim_left_matches("r#").to_owned() + ident.to_string().trim_start_matches("r#").to_owned() } diff --git a/src/internals/attr.rs b/src/internals/attr.rs index dc53248..9875b66 100644 --- a/src/internals/attr.rs +++ b/src/internals/attr.rs @@ -1,16 +1,15 @@ -use internals::respan::respan; use internals::symbol::*; use internals::{ungroup, Ctxt}; use proc_macro2::{Spacing, Span, TokenStream, TokenTree}; use quote::ToTokens; use std::borrow::Cow; use std::collections::BTreeSet; +use std::iter::FromIterator; use syn; -use syn::parse::{self, Parse, ParseStream}; +use syn::meta::ParseNestedMeta; +use syn::parse::ParseStream; use syn::punctuated::Punctuated; -use syn::Ident; -use syn::Meta::{List, NameValue, Path}; -use syn::NestedMeta::{Lit, Meta}; +use syn::{token, Ident, Lifetime}; // This module handles parsing of `#[serde(...)]` attributes. The entrypoints // are `attr::Container::from_ast`, `attr::Variant::from_ast`, and @@ -43,8 +42,8 @@ impl<'c, T> Attr<'c, T> { let tokens = obj.into_token_stream(); if self.value.is_some() { - self.cx - .error_spanned_by(tokens, format!("duplicate serde attribute `{}`", self.name)); + let msg = format!("duplicate serde attribute `{}`", self.name); + self.cx.error_spanned_by(tokens, msg); } else { self.tokens = tokens; self.value = Some(value); @@ -115,16 +114,14 @@ impl<'c, T> VecAttr<'c, T> { self.values.push(value); } - fn at_most_one(mut self) -> Result, ()> { + fn at_most_one(mut self) -> Option { if self.values.len() > 1 { let dup_token = self.first_dup_tokens; - self.cx.error_spanned_by( - dup_token, - format!("duplicate serde attribute `{}`", self.name), - ); - Err(()) + let msg = format!("duplicate serde attribute `{}`", self.name); + self.cx.error_spanned_by(dup_token, msg); + None } else { - Ok(self.values.pop()) + self.values.pop() } } @@ -141,12 +138,8 @@ pub struct Name { deserialize_aliases: Vec, } -#[allow(deprecated)] fn unraw(ident: &Ident) -> String { - // str::trim_start_matches was added in 1.30, trim_left_matches deprecated - // in 1.33. We currently support rustc back to 1.15 so we need to continue - // to use the deprecated one. - ident.to_string().trim_left_matches("r#").to_owned() + ident.to_string().trim_start_matches("r#").to_owned() } impl Name { @@ -309,285 +302,206 @@ impl Container { let mut serde_path = Attr::none(cx, CRATE); let mut expecting = Attr::none(cx, EXPECTING); - for meta_item in item - .attrs - .iter() - .flat_map(|attr| get_serde_meta_items(cx, attr)) - .flatten() - { - match &meta_item { - // Parse `#[serde(rename = "foo")]` - Meta(NameValue(m)) if m.path == RENAME => { - if let Ok(s) = get_lit_str(cx, RENAME, &m.lit) { - ser_name.set(&m.path, s.value()); - de_name.set(&m.path, s.value()); - } - } - - // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` - Meta(List(m)) if m.path == RENAME => { - if let Ok((ser, de)) = get_renames(cx, &m.nested) { - ser_name.set_opt(&m.path, ser.map(syn::LitStr::value)); - de_name.set_opt(&m.path, de.map(syn::LitStr::value)); - } - } + for attr in &item.attrs { + if attr.path() != SERDE { + continue; + } - // Parse `#[serde(rename_all = "foo")]` - Meta(NameValue(m)) if m.path == RENAME_ALL => { - if let Ok(s) = get_lit_str(cx, RENAME_ALL, &m.lit) { - match RenameRule::from_str(&s.value()) { - Ok(rename_rule) => { - rename_all_ser_rule.set(&m.path, rename_rule); - rename_all_de_rule.set(&m.path, rename_rule); - } - Err(err) => cx.error_spanned_by(s, err), + if let Err(err) = attr.parse_nested_meta(|meta| { + if meta.path == RENAME { + // #[serde(rename = "foo")] + // #[serde(rename(serialize = "foo", deserialize = "bar"))] + let (ser, de) = get_renames(cx, RENAME, &meta)?; + ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value)); + de_name.set_opt(&meta.path, de.as_ref().map(syn::LitStr::value)); + } else if meta.path == RENAME_ALL { + // #[serde(rename_all = "foo")] + // #[serde(rename_all(serialize = "foo", deserialize = "bar"))] + let one_name = meta.input.peek(Token![=]); + let (ser, de) = get_renames(cx, RENAME_ALL, &meta)?; + if let Some(ser) = ser { + match RenameRule::from_str(&ser.value()) { + Ok(rename_rule) => rename_all_ser_rule.set(&meta.path, rename_rule), + Err(err) => cx.error_spanned_by(ser, err), } } - } - - // Parse `#[serde(rename_all(serialize = "foo", deserialize = "bar"))]` - Meta(List(m)) if m.path == RENAME_ALL => { - if let Ok((ser, de)) = get_renames(cx, &m.nested) { - if let Some(ser) = ser { - match RenameRule::from_str(&ser.value()) { - Ok(rename_rule) => rename_all_ser_rule.set(&m.path, rename_rule), - Err(err) => cx.error_spanned_by(ser, err), - } - } - if let Some(de) = de { - match RenameRule::from_str(&de.value()) { - Ok(rename_rule) => rename_all_de_rule.set(&m.path, rename_rule), - Err(err) => cx.error_spanned_by(de, err), + if let Some(de) = de { + match RenameRule::from_str(&de.value()) { + Ok(rename_rule) => rename_all_de_rule.set(&meta.path, rename_rule), + Err(err) => { + if !one_name { + cx.error_spanned_by(de, err); + } } } } - } - - // Parse `#[serde(transparent)]` - Meta(Path(word)) if word == TRANSPARENT => { - transparent.set_true(word); - } - - // Parse `#[serde(deny_unknown_fields)]` - Meta(Path(word)) if word == DENY_UNKNOWN_FIELDS => { - deny_unknown_fields.set_true(word); - } - - // Parse `#[serde(default)]` - Meta(Path(word)) if word == DEFAULT => match &item.data { - syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { - syn::Fields::Named(_) => { - default.set(word, Default::Default); - } - syn::Fields::Unnamed(_) | syn::Fields::Unit => cx.error_spanned_by( - fields, - "#[serde(default)] can only be used on structs with named fields", - ), - }, - syn::Data::Enum(syn::DataEnum { enum_token, .. }) => cx.error_spanned_by( - enum_token, - "#[serde(default)] can only be used on structs with named fields", - ), - syn::Data::Union(syn::DataUnion { union_token, .. }) => cx.error_spanned_by( - union_token, - "#[serde(default)] can only be used on structs with named fields", - ), - }, - - // Parse `#[serde(default = "...")]` - Meta(NameValue(m)) if m.path == DEFAULT => { - if let Ok(path) = parse_lit_into_expr_path(cx, DEFAULT, &m.lit) { - match &item.data { - syn::Data::Struct(syn::DataStruct { fields, .. }) => { - match fields { + } else if meta.path == TRANSPARENT { + // #[serde(transparent)] + transparent.set_true(meta.path); + } else if meta.path == DENY_UNKNOWN_FIELDS { + // #[serde(deny_unknown_fields)] + deny_unknown_fields.set_true(meta.path); + } else if meta.path == DEFAULT { + if meta.input.peek(Token![=]) { + // #[serde(default = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? { + match &item.data { + syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { syn::Fields::Named(_) => { - default.set(&m.path, Default::Path(path)); + default.set(&meta.path, Default::Path(path)); + } + syn::Fields::Unnamed(_) | syn::Fields::Unit => { + let msg = "#[serde(default = \"...\")] can only be used on structs with named fields"; + cx.error_spanned_by(fields, msg); } - syn::Fields::Unnamed(_) | syn::Fields::Unit => cx - .error_spanned_by( - fields, - "#[serde(default = \"...\")] can only be used on structs with named fields", - ), + }, + syn::Data::Enum(syn::DataEnum { enum_token, .. }) => { + let msg = "#[serde(default = \"...\")] can only be used on structs with named fields"; + cx.error_spanned_by(enum_token, msg); + } + syn::Data::Union(syn::DataUnion { union_token, .. }) => { + let msg = "#[serde(default = \"...\")] can only be used on structs with named fields"; + cx.error_spanned_by(union_token, msg); } } - syn::Data::Enum(syn::DataEnum { enum_token, .. }) => cx - .error_spanned_by( - enum_token, - "#[serde(default = \"...\")] can only be used on structs with named fields", - ), - syn::Data::Union(syn::DataUnion { - union_token, .. - }) => cx.error_spanned_by( - union_token, - "#[serde(default = \"...\")] can only be used on structs with named fields", - ), + } + } else { + // #[serde(default)] + match &item.data { + syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { + syn::Fields::Named(_) => { + default.set(meta.path, Default::Default); + } + syn::Fields::Unnamed(_) | syn::Fields::Unit => { + let msg = "#[serde(default)] can only be used on structs with named fields"; + cx.error_spanned_by(fields, msg); + } + }, + syn::Data::Enum(syn::DataEnum { enum_token, .. }) => { + let msg = "#[serde(default)] can only be used on structs with named fields"; + cx.error_spanned_by(enum_token, msg); + } + syn::Data::Union(syn::DataUnion { union_token, .. }) => { + let msg = "#[serde(default)] can only be used on structs with named fields"; + cx.error_spanned_by(union_token, msg); + } } } - } - - // Parse `#[serde(bound = "T: SomeBound")]` - Meta(NameValue(m)) if m.path == BOUND => { - if let Ok(where_predicates) = parse_lit_into_where(cx, BOUND, BOUND, &m.lit) { - ser_bound.set(&m.path, where_predicates.clone()); - de_bound.set(&m.path, where_predicates); - } - } - - // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` - Meta(List(m)) if m.path == BOUND => { - if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { - ser_bound.set_opt(&m.path, ser); - de_bound.set_opt(&m.path, de); - } - } - - // Parse `#[serde(untagged)]` - Meta(Path(word)) if word == UNTAGGED => match item.data { - syn::Data::Enum(_) => { - untagged.set_true(word); - } - syn::Data::Struct(syn::DataStruct { struct_token, .. }) => { - cx.error_spanned_by( - struct_token, - "#[serde(untagged)] can only be used on enums", - ); - } - syn::Data::Union(syn::DataUnion { union_token, .. }) => { - cx.error_spanned_by( - union_token, - "#[serde(untagged)] can only be used on enums", - ); + } else if meta.path == BOUND { + // #[serde(bound = "T: SomeBound")] + // #[serde(bound(serialize = "...", deserialize = "..."))] + let (ser, de) = get_where_predicates(cx, &meta)?; + ser_bound.set_opt(&meta.path, ser); + de_bound.set_opt(&meta.path, de); + } else if meta.path == UNTAGGED { + // #[serde(untagged)] + match item.data { + syn::Data::Enum(_) => { + untagged.set_true(&meta.path); + } + syn::Data::Struct(syn::DataStruct { struct_token, .. }) => { + let msg = "#[serde(untagged)] can only be used on enums"; + cx.error_spanned_by(struct_token, msg); + } + syn::Data::Union(syn::DataUnion { union_token, .. }) => { + let msg = "#[serde(untagged)] can only be used on enums"; + cx.error_spanned_by(union_token, msg); + } } - }, - - // Parse `#[serde(tag = "type")]` - Meta(NameValue(m)) if m.path == TAG => { - if let Ok(s) = get_lit_str(cx, TAG, &m.lit) { + } else if meta.path == TAG { + // #[serde(tag = "type")] + if let Some(s) = get_lit_str(cx, TAG, &meta)? { match &item.data { syn::Data::Enum(_) => { - internal_tag.set(&m.path, s.value()); + internal_tag.set(&meta.path, s.value()); } syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { syn::Fields::Named(_) => { - internal_tag.set(&m.path, s.value()); + internal_tag.set(&meta.path, s.value()); } syn::Fields::Unnamed(_) | syn::Fields::Unit => { - cx.error_spanned_by( - fields, - "#[serde(tag = \"...\")] can only be used on enums and structs with named fields", - ); + let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields"; + cx.error_spanned_by(fields, msg); } }, syn::Data::Union(syn::DataUnion { union_token, .. }) => { - cx.error_spanned_by( - union_token, - "#[serde(tag = \"...\")] can only be used on enums and structs with named fields", - ); + let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields"; + cx.error_spanned_by(union_token, msg); } } } - } - - // Parse `#[serde(content = "c")]` - Meta(NameValue(m)) if m.path == CONTENT => { - if let Ok(s) = get_lit_str(cx, CONTENT, &m.lit) { + } else if meta.path == CONTENT { + // #[serde(content = "c")] + if let Some(s) = get_lit_str(cx, CONTENT, &meta)? { match &item.data { syn::Data::Enum(_) => { - content.set(&m.path, s.value()); + content.set(&meta.path, s.value()); } syn::Data::Struct(syn::DataStruct { struct_token, .. }) => { - cx.error_spanned_by( - struct_token, - "#[serde(content = \"...\")] can only be used on enums", - ); + let msg = "#[serde(content = \"...\")] can only be used on enums"; + cx.error_spanned_by(struct_token, msg); } syn::Data::Union(syn::DataUnion { union_token, .. }) => { - cx.error_spanned_by( - union_token, - "#[serde(content = \"...\")] can only be used on enums", - ); + let msg = "#[serde(content = \"...\")] can only be used on enums"; + cx.error_spanned_by(union_token, msg); } } } - } - - // Parse `#[serde(from = "Type")] - Meta(NameValue(m)) if m.path == FROM => { - if let Ok(from_ty) = parse_lit_into_ty(cx, FROM, &m.lit) { - type_from.set_opt(&m.path, Some(from_ty)); + } else if meta.path == FROM { + // #[serde(from = "Type")] + if let Some(from_ty) = parse_lit_into_ty(cx, FROM, &meta)? { + type_from.set_opt(&meta.path, Some(from_ty)); } - } - - // Parse `#[serde(try_from = "Type")] - Meta(NameValue(m)) if m.path == TRY_FROM => { - if let Ok(try_from_ty) = parse_lit_into_ty(cx, TRY_FROM, &m.lit) { - type_try_from.set_opt(&m.path, Some(try_from_ty)); + } else if meta.path == TRY_FROM { + // #[serde(try_from = "Type")] + if let Some(try_from_ty) = parse_lit_into_ty(cx, TRY_FROM, &meta)? { + type_try_from.set_opt(&meta.path, Some(try_from_ty)); } - } - - // Parse `#[serde(into = "Type")] - Meta(NameValue(m)) if m.path == INTO => { - if let Ok(into_ty) = parse_lit_into_ty(cx, INTO, &m.lit) { - type_into.set_opt(&m.path, Some(into_ty)); + } else if meta.path == INTO { + // #[serde(into = "Type")] + if let Some(into_ty) = parse_lit_into_ty(cx, INTO, &meta)? { + type_into.set_opt(&meta.path, Some(into_ty)); } - } - - // Parse `#[serde(remote = "...")]` - Meta(NameValue(m)) if m.path == REMOTE => { - if let Ok(path) = parse_lit_into_path(cx, REMOTE, &m.lit) { + } else if meta.path == REMOTE { + // #[serde(remote = "...")] + if let Some(path) = parse_lit_into_path(cx, REMOTE, &meta)? { if is_primitive_path(&path, "Self") { - remote.set(&m.path, item.ident.clone().into()); + remote.set(&meta.path, item.ident.clone().into()); } else { - remote.set(&m.path, path); + remote.set(&meta.path, path); } } - } - - // Parse `#[serde(field_identifier)]` - Meta(Path(word)) if word == FIELD_IDENTIFIER => { - field_identifier.set_true(word); - } - - // Parse `#[serde(variant_identifier)]` - Meta(Path(word)) if word == VARIANT_IDENTIFIER => { - variant_identifier.set_true(word); - } - - // 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); + } else if meta.path == FIELD_IDENTIFIER { + // #[serde(field_identifier)] + field_identifier.set_true(&meta.path); + } else if meta.path == VARIANT_IDENTIFIER { + // #[serde(variant_identifier)] + variant_identifier.set_true(&meta.path); + } else if meta.path == CRATE { + // #[serde(crate = "foo")] + if let Some(path) = parse_lit_into_path(cx, CRATE, &meta)? { + serde_path.set(&meta.path, path); } - } - - // Parse `#[serde(expecting = "a message")]` - Meta(NameValue(m)) if m.path == EXPECTING => { - if let Ok(s) = get_lit_str(cx, EXPECTING, &m.lit) { - expecting.set(&m.path, s.value()); + } else if meta.path == EXPECTING { + // #[serde(expecting = "a message")] + if let Some(s) = get_lit_str(cx, EXPECTING, &meta)? { + expecting.set(&meta.path, s.value()); } - } - - Meta(meta_item) => { - let path = meta_item - .path() - .into_token_stream() - .to_string() - .replace(' ', ""); - cx.error_spanned_by( - meta_item.path(), - format!("unknown serde container attribute `{}`", path), + } else { + let path = meta.path.to_token_stream().to_string().replace(' ', ""); + return Err( + meta.error(format_args!("unknown serde container attribute `{}`", path)) ); } - - Lit(lit) => { - cx.error_spanned_by(lit, "unexpected literal in serde container attribute"); - } + Ok(()) + }) { + cx.syn_error(err); } } let mut is_packed = false; for attr in &item.attrs { - if attr.path.is_ident("repr") { + if attr.path() == REPR { let _ = attr.parse_args_with(|input: ParseStream| { while let Some(token) = input.parse()? { if let TokenTree::Ident(ident) = token { @@ -725,10 +639,9 @@ fn decide_tag( syn::Fields::Named(_) | syn::Fields::Unit => {} syn::Fields::Unnamed(fields) => { if fields.unnamed.len() != 1 { - cx.error_spanned_by( - variant, - "#[serde(tag = \"...\")] cannot be used with tuple variants", - ); + let msg = + "#[serde(tag = \"...\")] cannot be used with tuple variants"; + cx.error_spanned_by(variant, msg); break; } } @@ -738,48 +651,28 @@ fn decide_tag( TagType::Internal { tag } } (Some((untagged_tokens, _)), Some((tag_tokens, _)), None) => { - cx.error_spanned_by( - untagged_tokens, - "enum cannot be both untagged and internally tagged", - ); - cx.error_spanned_by( - tag_tokens, - "enum cannot be both untagged and internally tagged", - ); + let msg = "enum cannot be both untagged and internally tagged"; + cx.error_spanned_by(untagged_tokens, msg); + cx.error_spanned_by(tag_tokens, msg); TagType::External // doesn't matter, will error } (None, None, Some((content_tokens, _))) => { - cx.error_spanned_by( - content_tokens, - "#[serde(tag = \"...\", content = \"...\")] must be used together", - ); + let msg = "#[serde(tag = \"...\", content = \"...\")] must be used together"; + cx.error_spanned_by(content_tokens, msg); TagType::External } (Some((untagged_tokens, _)), None, Some((content_tokens, _))) => { - cx.error_spanned_by( - untagged_tokens, - "untagged enum cannot have #[serde(content = \"...\")]", - ); - cx.error_spanned_by( - content_tokens, - "untagged enum cannot have #[serde(content = \"...\")]", - ); + let msg = "untagged enum cannot have #[serde(content = \"...\")]"; + cx.error_spanned_by(untagged_tokens, msg); + cx.error_spanned_by(content_tokens, msg); TagType::External } (None, Some((_, tag)), Some((_, content))) => TagType::Adjacent { tag, content }, (Some((untagged_tokens, _)), Some((tag_tokens, _)), Some((content_tokens, _))) => { - cx.error_spanned_by( - untagged_tokens, - "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", - ); - cx.error_spanned_by( - tag_tokens, - "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", - ); - cx.error_spanned_by( - content_tokens, - "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", - ); + let msg = "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]"; + cx.error_spanned_by(untagged_tokens, msg); + cx.error_spanned_by(tag_tokens, msg); + cx.error_spanned_by(content_tokens, msg); TagType::External } } @@ -798,44 +691,32 @@ fn decide_identifier( ) { (_, None, None) => Identifier::No, (_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => { - cx.error_spanned_by( - field_identifier_tokens, - "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set", - ); - cx.error_spanned_by( - variant_identifier_tokens, - "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set", - ); + let msg = + "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set"; + cx.error_spanned_by(field_identifier_tokens, msg); + cx.error_spanned_by(variant_identifier_tokens, msg); Identifier::No } (syn::Data::Enum(_), Some(_), None) => Identifier::Field, (syn::Data::Enum(_), None, Some(_)) => Identifier::Variant, (syn::Data::Struct(syn::DataStruct { struct_token, .. }), Some(_), None) => { - cx.error_spanned_by( - struct_token, - "#[serde(field_identifier)] can only be used on an enum", - ); + let msg = "#[serde(field_identifier)] can only be used on an enum"; + cx.error_spanned_by(struct_token, msg); Identifier::No } (syn::Data::Union(syn::DataUnion { union_token, .. }), Some(_), None) => { - cx.error_spanned_by( - union_token, - "#[serde(field_identifier)] can only be used on an enum", - ); + let msg = "#[serde(field_identifier)] can only be used on an enum"; + cx.error_spanned_by(union_token, msg); Identifier::No } (syn::Data::Struct(syn::DataStruct { struct_token, .. }), None, Some(_)) => { - cx.error_spanned_by( - struct_token, - "#[serde(variant_identifier)] can only be used on an enum", - ); + let msg = "#[serde(variant_identifier)] can only be used on an enum"; + cx.error_spanned_by(struct_token, msg); Identifier::No } (syn::Data::Union(syn::DataUnion { union_token, .. }), None, Some(_)) => { - cx.error_spanned_by( - union_token, - "#[serde(variant_identifier)] can only be used on an enum", - ); + let msg = "#[serde(variant_identifier)] can only be used on an enum"; + cx.error_spanned_by(union_token, msg); Identifier::No } } @@ -852,7 +733,12 @@ pub struct Variant { other: bool, serialize_with: Option, deserialize_with: Option, - borrow: Option, + borrow: Option, +} + +struct BorrowAttribute { + path: syn::Path, + lifetimes: Option>, } impl Variant { @@ -871,168 +757,125 @@ impl Variant { let mut deserialize_with = Attr::none(cx, DESERIALIZE_WITH); let mut borrow = Attr::none(cx, BORROW); - for meta_item in variant - .attrs - .iter() - .flat_map(|attr| get_serde_meta_items(cx, attr)) - .flatten() - { - match &meta_item { - // Parse `#[serde(rename = "foo")]` - Meta(NameValue(m)) if m.path == RENAME => { - if let Ok(s) = get_lit_str(cx, RENAME, &m.lit) { - ser_name.set(&m.path, s.value()); - de_name.set_if_none(s.value()); - de_aliases.insert(&m.path, s.value()); - } - } + for attr in &variant.attrs { + if attr.path() != SERDE { + continue; + } - // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` - Meta(List(m)) if m.path == RENAME => { - if let Ok((ser, de)) = get_multiple_renames(cx, &m.nested) { - ser_name.set_opt(&m.path, ser.map(syn::LitStr::value)); - for de_value in de { - de_name.set_if_none(de_value.value()); - de_aliases.insert(&m.path, de_value.value()); - } + if let Err(err) = attr.parse_nested_meta(|meta| { + if meta.path == RENAME { + // #[serde(rename = "foo")] + // #[serde(rename(serialize = "foo", deserialize = "bar"))] + let (ser, de) = get_multiple_renames(cx, &meta)?; + ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value)); + for de_value in de { + de_name.set_if_none(de_value.value()); + de_aliases.insert(&meta.path, de_value.value()); } - } - - // Parse `#[serde(alias = "foo")]` - Meta(NameValue(m)) if m.path == ALIAS => { - if let Ok(s) = get_lit_str(cx, ALIAS, &m.lit) { - de_aliases.insert(&m.path, s.value()); + } else if meta.path == ALIAS { + // #[serde(alias = "foo")] + if let Some(s) = get_lit_str(cx, ALIAS, &meta)? { + de_aliases.insert(&meta.path, s.value()); } - } - - // Parse `#[serde(rename_all = "foo")]` - Meta(NameValue(m)) if m.path == RENAME_ALL => { - if let Ok(s) = get_lit_str(cx, RENAME_ALL, &m.lit) { - match RenameRule::from_str(&s.value()) { - Ok(rename_rule) => { - rename_all_ser_rule.set(&m.path, rename_rule); - rename_all_de_rule.set(&m.path, rename_rule); - } - Err(err) => cx.error_spanned_by(s, err), + } else if meta.path == RENAME_ALL { + // #[serde(rename_all = "foo")] + // #[serde(rename_all(serialize = "foo", deserialize = "bar"))] + let one_name = meta.input.peek(Token![=]); + let (ser, de) = get_renames(cx, RENAME_ALL, &meta)?; + if let Some(ser) = ser { + match RenameRule::from_str(&ser.value()) { + Ok(rename_rule) => rename_all_ser_rule.set(&meta.path, rename_rule), + Err(err) => cx.error_spanned_by(ser, err), } } - } - - // Parse `#[serde(rename_all(serialize = "foo", deserialize = "bar"))]` - Meta(List(m)) if m.path == RENAME_ALL => { - if let Ok((ser, de)) = get_renames(cx, &m.nested) { - if let Some(ser) = ser { - match RenameRule::from_str(&ser.value()) { - Ok(rename_rule) => rename_all_ser_rule.set(&m.path, rename_rule), - Err(err) => cx.error_spanned_by(ser, err), - } - } - if let Some(de) = de { - match RenameRule::from_str(&de.value()) { - Ok(rename_rule) => rename_all_de_rule.set(&m.path, rename_rule), - Err(err) => cx.error_spanned_by(de, err), + if let Some(de) = de { + match RenameRule::from_str(&de.value()) { + Ok(rename_rule) => rename_all_de_rule.set(&meta.path, rename_rule), + Err(err) => { + if !one_name { + cx.error_spanned_by(de, err); + } } } } - } - - // Parse `#[serde(skip)]` - Meta(Path(word)) if word == SKIP => { - skip_serializing.set_true(word); - skip_deserializing.set_true(word); - } - - // Parse `#[serde(skip_deserializing)]` - Meta(Path(word)) if word == SKIP_DESERIALIZING => { - skip_deserializing.set_true(word); - } - - // Parse `#[serde(skip_serializing)]` - Meta(Path(word)) if word == SKIP_SERIALIZING => { - skip_serializing.set_true(word); - } - - // Parse `#[serde(other)]` - Meta(Path(word)) if word == OTHER => { - other.set_true(word); - } - - // Parse `#[serde(bound = "T: SomeBound")]` - Meta(NameValue(m)) if m.path == BOUND => { - if let Ok(where_predicates) = parse_lit_into_where(cx, BOUND, BOUND, &m.lit) { - ser_bound.set(&m.path, where_predicates.clone()); - de_bound.set(&m.path, where_predicates); - } - } - - // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` - Meta(List(m)) if m.path == BOUND => { - if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { - ser_bound.set_opt(&m.path, ser); - de_bound.set_opt(&m.path, de); - } - } - - // Parse `#[serde(with = "...")]` - Meta(NameValue(m)) if m.path == WITH => { - if let Ok(path) = parse_lit_into_expr_path(cx, WITH, &m.lit) { + } else if meta.path == SKIP { + // #[serde(skip)] + skip_serializing.set_true(&meta.path); + skip_deserializing.set_true(&meta.path); + } else if meta.path == SKIP_DESERIALIZING { + // #[serde(skip_deserializing)] + skip_deserializing.set_true(&meta.path); + } else if meta.path == SKIP_SERIALIZING { + // #[serde(skip_serializing)] + skip_serializing.set_true(&meta.path); + } else if meta.path == OTHER { + // #[serde(other)] + other.set_true(&meta.path); + } else if meta.path == BOUND { + // #[serde(bound = "T: SomeBound")] + // #[serde(bound(serialize = "...", deserialize = "..."))] + let (ser, de) = get_where_predicates(cx, &meta)?; + ser_bound.set_opt(&meta.path, ser); + de_bound.set_opt(&meta.path, de); + } else if meta.path == WITH { + // #[serde(with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, WITH, &meta)? { let mut ser_path = path.clone(); ser_path .path .segments .push(Ident::new("serialize", Span::call_site()).into()); - serialize_with.set(&m.path, ser_path); + serialize_with.set(&meta.path, ser_path); let mut de_path = path; de_path .path .segments .push(Ident::new("deserialize", Span::call_site()).into()); - deserialize_with.set(&m.path, de_path); + deserialize_with.set(&meta.path, de_path); } - } - - // Parse `#[serde(serialize_with = "...")]` - Meta(NameValue(m)) if m.path == SERIALIZE_WITH => { - if let Ok(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &m.lit) { - serialize_with.set(&m.path, path); + } else if meta.path == SERIALIZE_WITH { + // #[serde(serialize_with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &meta)? { + serialize_with.set(&meta.path, path); } - } - - // Parse `#[serde(deserialize_with = "...")]` - Meta(NameValue(m)) if m.path == DESERIALIZE_WITH => { - if let Ok(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &m.lit) { - deserialize_with.set(&m.path, path); - } - } - - // Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]` - Meta(m) if m.path() == BORROW => match &variant.fields { - syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { - borrow.set(m.path(), m.clone()); + } else if meta.path == DESERIALIZE_WITH { + // #[serde(deserialize_with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &meta)? { + deserialize_with.set(&meta.path, path); } - _ => { - cx.error_spanned_by( - variant, - "#[serde(borrow)] may only be used on newtype variants", - ); + } else if meta.path == BORROW { + let borrow_attribute = if meta.input.peek(Token![=]) { + // #[serde(borrow = "'a + 'b")] + let lifetimes = parse_lit_into_lifetimes(cx, &meta)?; + BorrowAttribute { + path: meta.path.clone(), + lifetimes: Some(lifetimes), + } + } else { + // #[serde(borrow)] + BorrowAttribute { + path: meta.path.clone(), + lifetimes: None, + } + }; + match &variant.fields { + syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { + borrow.set(&meta.path, borrow_attribute); + } + _ => { + let msg = "#[serde(borrow)] may only be used on newtype variants"; + cx.error_spanned_by(variant, msg); + } } - }, - - Meta(meta_item) => { - let path = meta_item - .path() - .into_token_stream() - .to_string() - .replace(' ', ""); - cx.error_spanned_by( - meta_item.path(), - format!("unknown serde variant attribute `{}`", path), + } else { + let path = meta.path.to_token_stream().to_string().replace(' ', ""); + return Err( + meta.error(format_args!("unknown serde variant attribute `{}`", path)) ); } - - Lit(lit) => { - cx.error_spanned_by(lit, "unexpected literal in serde variant attribute"); - } + Ok(()) + }) { + cx.syn_error(err); } } @@ -1168,182 +1011,139 @@ impl Field { None => index.to_string(), }; - let variant_borrow = attrs - .and_then(|variant| variant.borrow.as_ref()) - .map(|borrow| Meta(borrow.clone())); - - for meta_item in field - .attrs - .iter() - .flat_map(|attr| get_serde_meta_items(cx, attr)) - .flatten() - .chain(variant_borrow) - { - match &meta_item { - // Parse `#[serde(rename = "foo")]` - Meta(NameValue(m)) if m.path == RENAME => { - if let Ok(s) = get_lit_str(cx, RENAME, &m.lit) { - ser_name.set(&m.path, s.value()); - de_name.set_if_none(s.value()); - de_aliases.insert(&m.path, s.value()); - } - } - - // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` - Meta(List(m)) if m.path == RENAME => { - if let Ok((ser, de)) = get_multiple_renames(cx, &m.nested) { - ser_name.set_opt(&m.path, ser.map(syn::LitStr::value)); - for de_value in de { - de_name.set_if_none(de_value.value()); - de_aliases.insert(&m.path, de_value.value()); + if let Some(borrow_attribute) = attrs.and_then(|variant| variant.borrow.as_ref()) { + if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { + if let Some(lifetimes) = &borrow_attribute.lifetimes { + for lifetime in lifetimes { + if !borrowable.contains(lifetime) { + let msg = + format!("field `{}` does not have lifetime {}", ident, lifetime); + cx.error_spanned_by(field, msg); } } + borrowed_lifetimes.set(&borrow_attribute.path, lifetimes.clone()); + } else { + borrowed_lifetimes.set(&borrow_attribute.path, borrowable); } + } + } - // Parse `#[serde(alias = "foo")]` - Meta(NameValue(m)) if m.path == ALIAS => { - if let Ok(s) = get_lit_str(cx, ALIAS, &m.lit) { - de_aliases.insert(&m.path, s.value()); - } - } - - // Parse `#[serde(default)]` - Meta(Path(word)) if word == DEFAULT => { - default.set(word, Default::Default); - } + for attr in &field.attrs { + if attr.path() != SERDE { + continue; + } - // Parse `#[serde(default = "...")]` - Meta(NameValue(m)) if m.path == DEFAULT => { - if let Ok(path) = parse_lit_into_expr_path(cx, DEFAULT, &m.lit) { - default.set(&m.path, Default::Path(path)); + if let Err(err) = attr.parse_nested_meta(|meta| { + if meta.path == RENAME { + // #[serde(rename = "foo")] + // #[serde(rename(serialize = "foo", deserialize = "bar"))] + let (ser, de) = get_multiple_renames(cx, &meta)?; + ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value)); + for de_value in de { + de_name.set_if_none(de_value.value()); + de_aliases.insert(&meta.path, de_value.value()); } - } - - // Parse `#[serde(skip_serializing)]` - Meta(Path(word)) if word == SKIP_SERIALIZING => { - skip_serializing.set_true(word); - } - - // Parse `#[serde(skip_deserializing)]` - Meta(Path(word)) if word == SKIP_DESERIALIZING => { - skip_deserializing.set_true(word); - } - - // Parse `#[serde(skip)]` - Meta(Path(word)) if word == SKIP => { - skip_serializing.set_true(word); - skip_deserializing.set_true(word); - } - - // Parse `#[serde(skip_serializing_if = "...")]` - Meta(NameValue(m)) if m.path == SKIP_SERIALIZING_IF => { - if let Ok(path) = parse_lit_into_expr_path(cx, SKIP_SERIALIZING_IF, &m.lit) { - skip_serializing_if.set(&m.path, path); + } else if meta.path == ALIAS { + // #[serde(alias = "foo")] + if let Some(s) = get_lit_str(cx, ALIAS, &meta)? { + de_aliases.insert(&meta.path, s.value()); } - } - - // Parse `#[serde(serialize_with = "...")]` - Meta(NameValue(m)) if m.path == SERIALIZE_WITH => { - if let Ok(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &m.lit) { - serialize_with.set(&m.path, path); + } else if meta.path == DEFAULT { + if meta.input.peek(Token![=]) { + // #[serde(default = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? { + default.set(&meta.path, Default::Path(path)); + } + } else { + // #[serde(default)] + default.set(&meta.path, Default::Default); } - } - - // Parse `#[serde(deserialize_with = "...")]` - Meta(NameValue(m)) if m.path == DESERIALIZE_WITH => { - if let Ok(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &m.lit) { - deserialize_with.set(&m.path, path); + } else if meta.path == SKIP_SERIALIZING { + // #[serde(skip_serializing)] + skip_serializing.set_true(&meta.path); + } else if meta.path == SKIP_DESERIALIZING { + // #[serde(skip_deserializing)] + skip_deserializing.set_true(&meta.path); + } else if meta.path == SKIP { + // #[serde(skip)] + skip_serializing.set_true(&meta.path); + skip_deserializing.set_true(&meta.path); + } else if meta.path == SKIP_SERIALIZING_IF { + // #[serde(skip_serializing_if = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, SKIP_SERIALIZING_IF, &meta)? { + skip_serializing_if.set(&meta.path, path); } - } - - // Parse `#[serde(with = "...")]` - Meta(NameValue(m)) if m.path == WITH => { - if let Ok(path) = parse_lit_into_expr_path(cx, WITH, &m.lit) { + } else if meta.path == SERIALIZE_WITH { + // #[serde(serialize_with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &meta)? { + serialize_with.set(&meta.path, path); + } + } else if meta.path == DESERIALIZE_WITH { + // #[serde(deserialize_with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &meta)? { + deserialize_with.set(&meta.path, path); + } + } else if meta.path == WITH { + // #[serde(with = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, WITH, &meta)? { let mut ser_path = path.clone(); ser_path .path .segments .push(Ident::new("serialize", Span::call_site()).into()); - serialize_with.set(&m.path, ser_path); + serialize_with.set(&meta.path, ser_path); let mut de_path = path; de_path .path .segments .push(Ident::new("deserialize", Span::call_site()).into()); - deserialize_with.set(&m.path, de_path); - } - } - - // Parse `#[serde(bound = "T: SomeBound")]` - Meta(NameValue(m)) if m.path == BOUND => { - if let Ok(where_predicates) = parse_lit_into_where(cx, BOUND, BOUND, &m.lit) { - ser_bound.set(&m.path, where_predicates.clone()); - de_bound.set(&m.path, where_predicates); - } - } - - // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` - Meta(List(m)) if m.path == BOUND => { - if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { - ser_bound.set_opt(&m.path, ser); - de_bound.set_opt(&m.path, de); + deserialize_with.set(&meta.path, de_path); } - } - - // Parse `#[serde(borrow)]` - Meta(Path(word)) if word == BORROW => { - if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { - borrowed_lifetimes.set(word, borrowable); - } - } - - // Parse `#[serde(borrow = "'a + 'b")]` - Meta(NameValue(m)) if m.path == BORROW => { - if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, BORROW, &m.lit) { + } else if meta.path == BOUND { + // #[serde(bound = "T: SomeBound")] + // #[serde(bound(serialize = "...", deserialize = "..."))] + let (ser, de) = get_where_predicates(cx, &meta)?; + ser_bound.set_opt(&meta.path, ser); + de_bound.set_opt(&meta.path, de); + } else if meta.path == BORROW { + if meta.input.peek(Token![=]) { + // #[serde(borrow = "'a + 'b")] + let lifetimes = parse_lit_into_lifetimes(cx, &meta)?; if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { for lifetime in &lifetimes { if !borrowable.contains(lifetime) { - cx.error_spanned_by( - field, - format!( - "field `{}` does not have lifetime {}", - ident, lifetime - ), + let msg = format!( + "field `{}` does not have lifetime {}", + ident, lifetime, ); + cx.error_spanned_by(field, msg); } } - borrowed_lifetimes.set(&m.path, lifetimes); + borrowed_lifetimes.set(&meta.path, lifetimes); + } + } else { + // #[serde(borrow)] + if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { + borrowed_lifetimes.set(&meta.path, borrowable); } } - } - - // Parse `#[serde(getter = "...")]` - Meta(NameValue(m)) if m.path == GETTER => { - if let Ok(path) = parse_lit_into_expr_path(cx, GETTER, &m.lit) { - getter.set(&m.path, path); + } else if meta.path == GETTER { + // #[serde(getter = "...")] + if let Some(path) = parse_lit_into_expr_path(cx, GETTER, &meta)? { + getter.set(&meta.path, path); } - } - - // Parse `#[serde(flatten)]` - Meta(Path(word)) if word == FLATTEN => { - flatten.set_true(word); - } - - Meta(meta_item) => { - let path = meta_item - .path() - .into_token_stream() - .to_string() - .replace(' ', ""); - cx.error_spanned_by( - meta_item.path(), - format!("unknown serde field attribute `{}`", path), + } else if meta.path == FLATTEN { + // #[serde(flatten)] + flatten.set_true(&meta.path); + } else { + let path = meta.path.to_token_stream().to_string().replace(' ', ""); + return Err( + meta.error(format_args!("unknown serde field attribute `{}`", path)) ); } - - Lit(lit) => { - cx.error_spanned_by(lit, "unexpected literal in serde field attribute"); - } + Ok(()) + }) { + cx.syn_error(err); } } @@ -1497,130 +1297,154 @@ impl Field { type SerAndDe = (Option, Option); -fn get_ser_and_de<'a, 'b, T, F>( - cx: &'b Ctxt, +fn get_ser_and_de<'c, T, F, R>( + cx: &'c Ctxt, attr_name: Symbol, - metas: &'a Punctuated, + meta: &ParseNestedMeta, f: F, -) -> Result<(VecAttr<'b, T>, VecAttr<'b, T>), ()> +) -> syn::Result<(VecAttr<'c, T>, VecAttr<'c, T>)> where - T: 'a, - F: Fn(&Ctxt, Symbol, Symbol, &'a syn::Lit) -> Result, + T: Clone, + F: Fn(&Ctxt, Symbol, Symbol, &ParseNestedMeta) -> syn::Result, + R: Into>, { let mut ser_meta = VecAttr::none(cx, attr_name); let mut de_meta = VecAttr::none(cx, attr_name); - for meta in metas { - match meta { - Meta(NameValue(meta)) if meta.path == SERIALIZE => { - if let Ok(v) = f(cx, attr_name, SERIALIZE, &meta.lit) { + let lookahead = meta.input.lookahead1(); + if lookahead.peek(Token![=]) { + if let Some(both) = f(cx, attr_name, attr_name, meta)?.into() { + ser_meta.insert(&meta.path, both.clone()); + de_meta.insert(&meta.path, both); + } + } else if lookahead.peek(token::Paren) { + meta.parse_nested_meta(|meta| { + if meta.path == SERIALIZE { + if let Some(v) = f(cx, attr_name, SERIALIZE, &meta)?.into() { ser_meta.insert(&meta.path, v); } - } - - Meta(NameValue(meta)) if meta.path == DESERIALIZE => { - if let Ok(v) = f(cx, attr_name, DESERIALIZE, &meta.lit) { + } else if meta.path == DESERIALIZE { + if let Some(v) = f(cx, attr_name, DESERIALIZE, &meta)?.into() { de_meta.insert(&meta.path, v); } + } else { + return Err(meta.error(format_args!( + "malformed {0} attribute, expected `{0}(serialize = ..., deserialize = ...)`", + attr_name, + ))); } - - _ => { - cx.error_spanned_by( - meta, - format!( - "malformed {0} attribute, expected `{0}(serialize = ..., deserialize = ...)`", - attr_name - ), - ); - return Err(()); - } - } + Ok(()) + })?; + } else { + return Err(lookahead.error()); } Ok((ser_meta, de_meta)) } -fn get_renames<'a>( +fn get_renames( cx: &Ctxt, - items: &'a Punctuated, -) -> Result, ()> { - let (ser, de) = get_ser_and_de(cx, RENAME, items, get_lit_str2)?; - Ok((ser.at_most_one()?, de.at_most_one()?)) + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result> { + let (ser, de) = get_ser_and_de(cx, attr_name, meta, get_lit_str2)?; + Ok((ser.at_most_one(), de.at_most_one())) } -fn get_multiple_renames<'a>( +fn get_multiple_renames( cx: &Ctxt, - items: &'a Punctuated, -) -> Result<(Option<&'a syn::LitStr>, Vec<&'a syn::LitStr>), ()> { - let (ser, de) = get_ser_and_de(cx, RENAME, items, get_lit_str2)?; - Ok((ser.at_most_one()?, de.get())) + meta: &ParseNestedMeta, +) -> syn::Result<(Option, Vec)> { + let (ser, de) = get_ser_and_de(cx, RENAME, meta, get_lit_str2)?; + Ok((ser.at_most_one(), de.get())) } fn get_where_predicates( cx: &Ctxt, - items: &Punctuated, -) -> Result>, ()> { - let (ser, de) = get_ser_and_de(cx, BOUND, items, parse_lit_into_where)?; - Ok((ser.at_most_one()?, de.at_most_one()?)) -} - -pub fn get_serde_meta_items(cx: &Ctxt, attr: &syn::Attribute) -> Result, ()> { - if attr.path != SERDE { - return Ok(Vec::new()); - } - - match attr.parse_meta() { - Ok(List(meta)) => Ok(meta.nested.into_iter().collect()), - Ok(other) => { - cx.error_spanned_by(other, "expected #[serde(...)]"); - Err(()) - } - Err(err) => { - cx.syn_error(err); - Err(()) - } - } + meta: &ParseNestedMeta, +) -> syn::Result>> { + let (ser, de) = get_ser_and_de(cx, BOUND, meta, parse_lit_into_where)?; + Ok((ser.at_most_one(), de.at_most_one())) } -fn get_lit_str<'a>(cx: &Ctxt, attr_name: Symbol, lit: &'a syn::Lit) -> Result<&'a syn::LitStr, ()> { - get_lit_str2(cx, attr_name, attr_name, lit) +fn get_lit_str( + cx: &Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result> { + get_lit_str2(cx, attr_name, attr_name, meta) } -fn get_lit_str2<'a>( +fn get_lit_str2( cx: &Ctxt, attr_name: Symbol, meta_item_name: Symbol, - lit: &'a syn::Lit, -) -> Result<&'a syn::LitStr, ()> { - if let syn::Lit::Str(lit) = lit { - Ok(lit) + meta: &ParseNestedMeta, +) -> syn::Result> { + let expr: syn::Expr = meta.value()?.parse()?; + let mut value = &expr; + while let syn::Expr::Group(e) = value { + value = &e.expr; + } + if let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit), + .. + }) = value + { + Ok(Some(lit.clone())) } else { cx.error_spanned_by( - lit, + expr, format!( "expected serde {} attribute to be a string: `{} = \"...\"`", attr_name, meta_item_name ), ); - Err(()) + Ok(None) } } -fn parse_lit_into_path(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result { - 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())); +fn parse_lit_into_path( + cx: &Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result> { + let string = match get_lit_str(cx, attr_name, meta)? { + Some(string) => string, + None => return Ok(None), + }; + + Ok(match string.parse() { + Ok(path) => Some(path), + Err(_) => { + cx.error_spanned_by( + &string, + format!("failed to parse path: {:?}", string.value()), + ); + None + } }) } fn parse_lit_into_expr_path( cx: &Ctxt, attr_name: Symbol, - lit: &syn::Lit, -) -> Result { - 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())); + meta: &ParseNestedMeta, +) -> syn::Result> { + let string = match get_lit_str(cx, attr_name, meta)? { + Some(string) => string, + None => return Ok(None), + }; + + Ok(match string.parse() { + Ok(expr) => Some(expr), + Err(_) => { + cx.error_spanned_by( + &string, + format!("failed to parse path: {:?}", string.value()), + ); + None + } }) } @@ -1628,28 +1452,43 @@ fn parse_lit_into_where( cx: &Ctxt, attr_name: Symbol, meta_item_name: Symbol, - lit: &syn::Lit, -) -> Result, ()> { - let string = get_lit_str2(cx, attr_name, meta_item_name, lit)?; - if string.value().is_empty() { - return Ok(Vec::new()); - } - - let where_string = syn::LitStr::new(&format!("where {}", string.value()), string.span()); + meta: &ParseNestedMeta, +) -> syn::Result> { + let string = match get_lit_str2(cx, attr_name, meta_item_name, meta)? { + Some(string) => string, + None => return Ok(Vec::new()), + }; - parse_lit_str::(&where_string) - .map(|wh| wh.predicates.into_iter().collect()) - .map_err(|err| cx.error_spanned_by(lit, err)) + Ok( + match string.parse_with(Punctuated::::parse_terminated) { + Ok(predicates) => Vec::from_iter(predicates), + Err(err) => { + cx.error_spanned_by(string, err); + Vec::new() + } + }, + ) } -fn parse_lit_into_ty(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result { - let string = get_lit_str(cx, attr_name, lit)?; +fn parse_lit_into_ty( + cx: &Ctxt, + attr_name: Symbol, + meta: &ParseNestedMeta, +) -> syn::Result> { + let string = match get_lit_str(cx, attr_name, meta)? { + Some(string) => string, + None => return Ok(None), + }; - parse_lit_str(string).map_err(|_| { - cx.error_spanned_by( - lit, - format!("failed to parse type: {} = {:?}", attr_name, string.value()), - ); + Ok(match string.parse() { + Ok(ty) => Some(ty), + Err(_) => { + cx.error_spanned_by( + &string, + format!("failed to parse type: {} = {:?}", attr_name, string.value()), + ); + None + } }) } @@ -1657,38 +1496,41 @@ fn parse_lit_into_ty(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result Result, ()> { - let string = get_lit_str(cx, attr_name, lit)?; - if string.value().is_empty() { - cx.error_spanned_by(lit, "at least one lifetime must be borrowed"); - return Err(()); - } - - struct BorrowedLifetimes(Punctuated); - - impl Parse for BorrowedLifetimes { - fn parse(input: ParseStream) -> parse::Result { - Punctuated::parse_separated_nonempty(input).map(BorrowedLifetimes) - } - } + meta: &ParseNestedMeta, +) -> syn::Result> { + let string = match get_lit_str(cx, BORROW, meta)? { + Some(string) => string, + None => return Ok(BTreeSet::new()), + }; - if let Ok(BorrowedLifetimes(lifetimes)) = parse_lit_str(string) { + if let Ok(lifetimes) = string.parse_with(|input: ParseStream| { let mut set = BTreeSet::new(); - for lifetime in lifetimes { + while !input.is_empty() { + let lifetime: Lifetime = input.parse()?; if !set.insert(lifetime.clone()) { - cx.error_spanned_by(lit, format!("duplicate borrowed lifetime `{}`", lifetime)); + cx.error_spanned_by( + &string, + format!("duplicate borrowed lifetime `{}`", lifetime), + ); } + if input.is_empty() { + break; + } + input.parse::()?; + } + Ok(set) + }) { + if lifetimes.is_empty() { + cx.error_spanned_by(string, "at least one lifetime must be borrowed"); } - return Ok(set); + return Ok(lifetimes); } cx.error_spanned_by( - lit, + &string, format!("failed to parse borrowed lifetimes: {:?}", string.value()), ); - Err(()) + Ok(BTreeSet::new()) } fn is_implicitly_borrowed(ty: &syn::Type) -> bool { @@ -1842,10 +1684,8 @@ fn borrowable_lifetimes( let mut lifetimes = BTreeSet::new(); collect_lifetimes(&field.ty, &mut lifetimes); if lifetimes.is_empty() { - cx.error_spanned_by( - field, - format!("field `{}` has no lifetimes to borrow", name), - ); + let msg = format!("field `{}` has no lifetimes to borrow", name); + cx.error_spanned_by(field, msg); Err(()) } else { Ok(lifetimes) @@ -1886,11 +1726,10 @@ fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet) { syn::GenericArgument::Type(ty) => { collect_lifetimes(ty, out); } - syn::GenericArgument::Binding(binding) => { + syn::GenericArgument::AssocType(binding) => { collect_lifetimes(&binding.ty, out); } - syn::GenericArgument::Constraint(_) - | syn::GenericArgument::Const(_) => {} + _ => {} } } } @@ -1937,16 +1776,3 @@ fn collect_lifetimes_from_tokens(tokens: TokenStream, out: &mut BTreeSet(s: &syn::LitStr) -> parse::Result -where - T: Parse, -{ - let tokens = spanned_tokens(s)?; - syn::parse2(tokens) -} - -fn spanned_tokens(s: &syn::LitStr) -> parse::Result { - let stream = syn::parse_str(&s.value())?; - Ok(respan(stream, s.span())) -} diff --git a/src/internals/check.rs b/src/internals/check.rs index eb1297a..05b4b8f 100644 --- a/src/internals/check.rs +++ b/src/internals/check.rs @@ -3,8 +3,8 @@ use internals::attr::{Identifier, TagType}; use internals::{ungroup, Ctxt, Derive}; use syn::{Member, Type}; -/// Cross-cutting checks that require looking at more than a single attrs -/// object. Simpler checks should happen when parsing and building the attrs. +// Cross-cutting checks that require looking at more than a single attrs object. +// Simpler checks should happen when parsing and building the attrs. pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { check_remote_generic(cx, cont); check_getter(cx, cont); @@ -17,18 +17,18 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { check_from_and_try_from(cx, cont); } -/// Remote derive definition type must have either all of the generics of the -/// remote type: -/// -/// #[serde(remote = "Generic")] -/// struct Generic {…} -/// -/// or none of them, i.e. defining impls for one concrete instantiation of the -/// remote type only: -/// -/// #[serde(remote = "Generic")] -/// struct ConcreteDef {…} -/// +// Remote derive definition type must have either all of the generics of the +// remote type: +// +// #[serde(remote = "Generic")] +// struct Generic {…} +// +// or none of them, i.e. defining impls for one concrete instantiation of the +// remote type only: +// +// #[serde(remote = "Generic")] +// struct ConcreteDef {…} +// fn check_remote_generic(cx: &Ctxt, cont: &Container) { if let Some(remote) = cont.attrs.remote() { let local_has_generic = !cont.generics.params.is_empty(); @@ -39,8 +39,8 @@ fn check_remote_generic(cx: &Ctxt, cont: &Container) { } } -/// Getters are only allowed inside structs (not enums) with the `remote` -/// attribute. +// Getters are only allowed inside structs (not enums) with the `remote` +// attribute. fn check_getter(cx: &Ctxt, cont: &Container) { match cont.data { Data::Enum(_) => { @@ -62,7 +62,7 @@ fn check_getter(cx: &Ctxt, cont: &Container) { } } -/// Flattening has some restrictions we can test. +// Flattening has some restrictions we can test. fn check_flatten(cx: &Ctxt, cont: &Container) { match &cont.data { Data::Enum(variants) => { @@ -101,12 +101,12 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) { } } -/// The `other` attribute must be used at most once and it must be the last -/// variant of an enum. -/// -/// Inside a `variant_identifier` all variants must be unit variants. Inside a -/// `field_identifier` all but possibly one variant must be unit variants. The -/// last variant may be a newtype variant which is an implicit "other" case. +// The `other` attribute must be used at most once and it must be the last +// variant of an enum. +// +// Inside a `variant_identifier` all variants must be unit variants. Inside a +// `field_identifier` all but possibly one variant must be unit variants. The +// last variant may be a newtype variant which is an implicit "other" case. fn check_identifier(cx: &Ctxt, cont: &Container) { let variants = match &cont.data { Data::Enum(variants) => variants, @@ -189,8 +189,8 @@ fn check_identifier(cx: &Ctxt, cont: &Container) { } } -/// Skip-(de)serializing attributes are not allowed on variants marked -/// (de)serialize_with. +// Skip-(de)serializing attributes are not allowed on variants marked +// (de)serialize_with. fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { let variants = match &cont.data { Data::Enum(variants) => variants, @@ -264,10 +264,9 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { } } -/// The tag of an internally-tagged struct variant must not be -/// the same as either one of its fields, as this would result in -/// duplicate keys in the serialized output and/or ambiguity in -/// the to-be-deserialized input. +// The tag of an internally-tagged struct variant must not be the same as either +// one of its fields, as this would result in duplicate keys in the serialized +// output and/or ambiguity in the to-be-deserialized input. fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { let variants = match &cont.data { Data::Enum(variants) => variants, @@ -313,8 +312,8 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { } } -/// In the case of adjacently-tagged enums, the type and the -/// contents tag must differ, for the same reason. +// In the case of adjacently-tagged enums, the type and the contents tag must +// differ, for the same reason. fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { let (type_tag, content_tag) = match cont.attrs.tag() { TagType::Adjacent { tag, content } => (tag, content), @@ -332,7 +331,7 @@ fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { } } -/// Enums and unit structs cannot be transparent. +// Enums and unit structs cannot be transparent. fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { if !cont.attrs.transparent() { return; diff --git a/src/internals/receiver.rs b/src/internals/receiver.rs index b08c670..5dc01db 100644 --- a/src/internals/receiver.rs +++ b/src/internals/receiver.rs @@ -179,10 +179,13 @@ impl ReplaceReceiver<'_> { for arg in &mut arguments.args { match arg { GenericArgument::Type(arg) => self.visit_type_mut(arg), - GenericArgument::Binding(arg) => self.visit_type_mut(&mut arg.ty), + GenericArgument::AssocType(arg) => self.visit_type_mut(&mut arg.ty), GenericArgument::Lifetime(_) - | GenericArgument::Constraint(_) - | GenericArgument::Const(_) => {} + | GenericArgument::Const(_) + | GenericArgument::AssocConst(_) + | GenericArgument::Constraint(_) => {} + #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + _ => {} } } } @@ -205,7 +208,9 @@ impl ReplaceReceiver<'_> { fn visit_type_param_bound_mut(&mut self, bound: &mut TypeParamBound) { match bound { TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path), - TypeParamBound::Lifetime(_) => {} + TypeParamBound::Lifetime(_) | TypeParamBound::Verbatim(_) => {} + #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + _ => {} } } @@ -229,7 +234,9 @@ impl ReplaceReceiver<'_> { self.visit_type_param_bound_mut(bound); } } - WherePredicate::Lifetime(_) | WherePredicate::Eq(_) => {} + WherePredicate::Lifetime(_) => {} + #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + _ => {} } } } diff --git a/src/internals/symbol.rs b/src/internals/symbol.rs index 1fedd27..9606edb 100644 --- a/src/internals/symbol.rs +++ b/src/internals/symbol.rs @@ -13,6 +13,7 @@ pub const DEFAULT: Symbol = Symbol("default"); pub const DENY_UNKNOWN_FIELDS: Symbol = Symbol("deny_unknown_fields"); pub const DESERIALIZE: Symbol = Symbol("deserialize"); pub const DESERIALIZE_WITH: Symbol = Symbol("deserialize_with"); +pub const EXPECTING: Symbol = Symbol("expecting"); pub const FIELD_IDENTIFIER: Symbol = Symbol("field_identifier"); pub const FLATTEN: Symbol = Symbol("flatten"); pub const FROM: Symbol = Symbol("from"); @@ -22,6 +23,7 @@ pub const OTHER: Symbol = Symbol("other"); pub const REMOTE: Symbol = Symbol("remote"); pub const RENAME: Symbol = Symbol("rename"); pub const RENAME_ALL: Symbol = Symbol("rename_all"); +pub const REPR: Symbol = Symbol("repr"); pub const SERDE: Symbol = Symbol("serde"); pub const SERIALIZE: Symbol = Symbol("serialize"); pub const SERIALIZE_WITH: Symbol = Symbol("serialize_with"); @@ -35,7 +37,6 @@ pub const TRY_FROM: Symbol = Symbol("try_from"); pub const UNTAGGED: Symbol = Symbol("untagged"); pub const VARIANT_IDENTIFIER: Symbol = Symbol("variant_identifier"); pub const WITH: Symbol = Symbol("with"); -pub const EXPECTING: Symbol = Symbol("expecting"); impl PartialEq for Ident { fn eq(&self, word: &Symbol) -> bool { diff --git a/src/lib.rs b/src/lib.rs index 4100789..eda4acb 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.152")] +#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.158")] #![allow(unknown_lints, bare_trait_objects)] // Ignored clippy lints #![allow( @@ -43,6 +43,7 @@ clippy::enum_glob_use, clippy::indexing_slicing, clippy::items_after_statements, + clippy::let_underscore_untyped, clippy::manual_assert, clippy::map_err_ignore, clippy::match_same_arms, -- cgit v1.2.3