Compare commits

...

12 Commits

Author SHA1 Message Date
David Tolnay 0676673ca5 Release 1.0.177 2023-07-27 10:51:22 -07:00
David Tolnay 7a4335d664 Merge pull request #2536 from jplatte/jplatte/error-span
Update error span for attribute / data kind mismatches
2023-07-27 10:50:26 -07:00
Jonas Platte 31a0e73489 Update error span for attribute / data kind mismatches 2023-07-27 10:47:45 +02:00
David Tolnay 74fe70855f Ignore return_self_not_must_use pedantic clippy lint
warning: missing `#[must_use]` attribute on a method returning `Self`
       --> serde_derive_internals/src/attr.rs:204:5
        |
    204 | /     pub fn or(self, other_rules: Self) -> Self {
    205 | |         Self {
    206 | |             serialize: self.serialize.or(other_rules.serialize),
    207 | |             deserialize: self.deserialize.or(other_rules.deserialize),
    208 | |         }
    209 | |     }
        | |_____^
        |
        = help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
        = note: `-W clippy::return-self-not-must-use` implied by `-W clippy::pedantic`

    warning: missing `#[must_use]` attribute on a method returning `Self`
       --> serde_derive_internals/src/case.rs:112:5
        |
    112 | /     pub fn or(self, rule_b: Self) -> Self {
    113 | |         match self {
    114 | |             None => rule_b,
    115 | |             _ => self,
    116 | |         }
    117 | |     }
        | |_____^
        |
        = help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
2023-07-27 00:51:57 -07:00
David Tolnay e74925bc43 Merge pull request #1695 from jplatte/rename_all_fields
Add #[serde(rename_all_fields = "foo")] attribute
2023-07-27 00:45:45 -07:00
Jonas Platte 56be1c203e Pass RenameRule, RenameAllRules by value 2023-07-27 09:19:42 +02:00
Jonas Platte 2f9bf4d3eb Add #[serde(rename_all_fields = "foo")] attribute 2023-07-27 09:19:42 +02:00
David Tolnay ad94aed753 Merge pull request #2535 from dtolnay/baretrait
Restore bare_trait_objects lint within serde_derive code
2023-07-26 14:26:02 -07:00
David Tolnay 30db83fc44 Restore bare_trait_objects lint within serde_derive code 2023-07-26 14:18:25 -07:00
David Tolnay b0f7b00e1f Resolve manual_string_new pedantic clippy lint
warning: empty String is being created manually
        --> test_suite/tests/test_annotations.rs:2280:29
         |
    2280 |     let data = Data::C { t: "".to_string() };
         |                             ^^^^^^^^^^^^^^ help: consider using: `String::new()`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_string_new
         = note: `-W clippy::manual-string-new` implied by `-W clippy::pedantic`
2023-07-26 13:46:28 -07:00
David Tolnay 7255e192d8 Delete unused statement from PR 2266 test 2023-07-26 13:45:49 -07:00
David Tolnay 2102e1aa42 Format PR 2266 tests with rustfmt 2023-07-26 13:41:56 -07:00
20 changed files with 204 additions and 77 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.176"
version = "1.0.177"
authors = ["David Tolnay <dtolnay@gmail.com>"]
publish = false
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.176"
version = "1.0.177"
authors = ["David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std", "no-std::no-alloc"]
description = "Implementation of #[derive(Serialize, Deserialize)]"
+1 -2
View File
@@ -13,8 +13,7 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.176")]
#![allow(unknown_lints, bare_trait_objects)]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.177")]
#[cfg(not(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu")))]
include!("lib_from_source.rs");
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.176" # remember to update html_root_url and serde_derive dependency
version = "1.0.177" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["encoding", "no-std", "no-std::no-alloc"]
@@ -14,7 +14,7 @@ repository = "https://github.com/serde-rs/serde"
rust-version = "1.19"
[dependencies]
serde_derive = { version = "=1.0.176", optional = true, path = "../serde_derive" }
serde_derive = { version = "=1.0.177", optional = true, path = "../serde_derive" }
[dev-dependencies]
serde_derive = { version = "1", path = "../serde_derive" }
+1 -1
View File
@@ -93,7 +93,7 @@
////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.176")]
#![doc(html_root_url = "https://docs.rs/serde/1.0.177")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.176" # remember to update html_root_url
version = "1.0.177" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std", "no-std::no-alloc"]
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
+7 -4
View File
@@ -86,9 +86,12 @@ impl<'a> Container<'a> {
if field.attrs.flatten() {
has_flatten = true;
}
field
.attrs
.rename_by_rules(variant.attrs.rename_all_rules());
field.attrs.rename_by_rules(
variant
.attrs
.rename_all_rules()
.or(attrs.rename_all_fields_rules()),
);
}
}
}
@@ -119,7 +122,7 @@ impl<'a> Container<'a> {
}
impl<'a> Data<'a> {
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
pub fn all_fields(&'a self) -> Box<dyn Iterator<Item = &'a Field<'a>> + 'a> {
match self {
Data::Enum(variants) => {
Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
+87 -26
View File
@@ -192,11 +192,23 @@ impl Name {
}
}
#[derive(Copy, Clone)]
pub struct RenameAllRules {
serialize: RenameRule,
deserialize: RenameRule,
}
impl RenameAllRules {
/// Returns a new `RenameAllRules` with the individual rules of `self` and
/// `other_rules` joined by `RenameRules::or`.
pub fn or(self, other_rules: Self) -> Self {
Self {
serialize: self.serialize.or(other_rules.serialize),
deserialize: self.deserialize.or(other_rules.deserialize),
}
}
}
/// Represents struct or enum attribute information.
pub struct Container {
name: Name,
@@ -204,6 +216,7 @@ pub struct Container {
deny_unknown_fields: bool,
default: Default,
rename_all_rules: RenameAllRules,
rename_all_fields_rules: RenameAllRules,
ser_bound: Option<Vec<syn::WherePredicate>>,
de_bound: Option<Vec<syn::WherePredicate>>,
tag: TagType,
@@ -287,6 +300,8 @@ impl Container {
let mut default = Attr::none(cx, DEFAULT);
let mut rename_all_ser_rule = Attr::none(cx, RENAME_ALL);
let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL);
let mut rename_all_fields_ser_rule = Attr::none(cx, RENAME_ALL_FIELDS);
let mut rename_all_fields_de_rule = Attr::none(cx, RENAME_ALL_FIELDS);
let mut ser_bound = Attr::none(cx, BOUND);
let mut de_bound = Attr::none(cx, BOUND);
let mut untagged = BoolAttr::none(cx, UNTAGGED);
@@ -340,6 +355,44 @@ impl Container {
}
}
}
} else if meta.path == RENAME_ALL_FIELDS {
// #[serde(rename_all_fields = "foo")]
// #[serde(rename_all_fields(serialize = "foo", deserialize = "bar"))]
let one_name = meta.input.peek(Token![=]);
let (ser, de) = get_renames(cx, RENAME_ALL_FIELDS, &meta)?;
match item.data {
syn::Data::Enum(_) => {
if let Some(ser) = ser {
match RenameRule::from_str(&ser.value()) {
Ok(rename_rule) => {
rename_all_fields_ser_rule.set(&meta.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_fields_de_rule.set(&meta.path, rename_rule);
}
Err(err) => {
if !one_name {
cx.error_spanned_by(de, err);
}
}
}
}
}
syn::Data::Struct(_) => {
let msg = "#[serde(rename_all_fields)] can only be used on enums";
cx.syn_error(meta.error(msg));
}
syn::Data::Union(_) => {
let msg = "#[serde(rename_all_fields)] can only be used on enums";
cx.syn_error(meta.error(msg));
}
}
} else if meta.path == TRANSPARENT {
// #[serde(transparent)]
transparent.set_true(meta.path);
@@ -357,16 +410,16 @@ impl Container {
}
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);
cx.syn_error(meta.error(msg));
}
},
syn::Data::Enum(syn::DataEnum { enum_token, .. }) => {
syn::Data::Enum(_) => {
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
cx.error_spanned_by(enum_token, msg);
cx.syn_error(meta.error(msg));
}
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
syn::Data::Union(_) => {
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
cx.error_spanned_by(union_token, msg);
cx.syn_error(meta.error(msg));
}
}
}
@@ -382,13 +435,13 @@ impl Container {
cx.error_spanned_by(fields, msg);
}
},
syn::Data::Enum(syn::DataEnum { enum_token, .. }) => {
syn::Data::Enum(_) => {
let msg = "#[serde(default)] can only be used on structs with named fields";
cx.error_spanned_by(enum_token, msg);
cx.syn_error(meta.error(msg));
}
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
syn::Data::Union(_) => {
let msg = "#[serde(default)] can only be used on structs with named fields";
cx.error_spanned_by(union_token, msg);
cx.syn_error(meta.error(msg));
}
}
}
@@ -404,13 +457,13 @@ impl Container {
syn::Data::Enum(_) => {
untagged.set_true(&meta.path);
}
syn::Data::Struct(syn::DataStruct { struct_token, .. }) => {
syn::Data::Struct(_) => {
let msg = "#[serde(untagged)] can only be used on enums";
cx.error_spanned_by(struct_token, msg);
cx.syn_error(meta.error(msg));
}
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
syn::Data::Union(_) => {
let msg = "#[serde(untagged)] can only be used on enums";
cx.error_spanned_by(union_token, msg);
cx.syn_error(meta.error(msg));
}
}
} else if meta.path == TAG {
@@ -426,12 +479,12 @@ impl Container {
}
syn::Fields::Unnamed(_) | syn::Fields::Unit => {
let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields";
cx.error_spanned_by(fields, msg);
cx.syn_error(meta.error(msg));
}
},
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
syn::Data::Union(_) => {
let msg = "#[serde(tag = \"...\")] can only be used on enums and structs with named fields";
cx.error_spanned_by(union_token, msg);
cx.syn_error(meta.error(msg));
}
}
}
@@ -442,13 +495,13 @@ impl Container {
syn::Data::Enum(_) => {
content.set(&meta.path, s.value());
}
syn::Data::Struct(syn::DataStruct { struct_token, .. }) => {
syn::Data::Struct(_) => {
let msg = "#[serde(content = \"...\")] can only be used on enums";
cx.error_spanned_by(struct_token, msg);
cx.syn_error(meta.error(msg));
}
syn::Data::Union(syn::DataUnion { union_token, .. }) => {
syn::Data::Union(_) => {
let msg = "#[serde(content = \"...\")] can only be used on enums";
cx.error_spanned_by(union_token, msg);
cx.syn_error(meta.error(msg));
}
}
}
@@ -527,6 +580,10 @@ impl Container {
serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None),
deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None),
},
rename_all_fields_rules: RenameAllRules {
serialize: rename_all_fields_ser_rule.get().unwrap_or(RenameRule::None),
deserialize: rename_all_fields_de_rule.get().unwrap_or(RenameRule::None),
},
ser_bound: ser_bound.get(),
de_bound: de_bound.get(),
tag: decide_tag(cx, item, untagged, internal_tag, content),
@@ -546,8 +603,12 @@ impl Container {
&self.name
}
pub fn rename_all_rules(&self) -> &RenameAllRules {
&self.rename_all_rules
pub fn rename_all_rules(&self) -> RenameAllRules {
self.rename_all_rules
}
pub fn rename_all_fields_rules(&self) -> RenameAllRules {
self.rename_all_fields_rules
}
pub fn transparent(&self) -> bool {
@@ -920,7 +981,7 @@ impl Variant {
self.name.deserialize_aliases()
}
pub fn rename_by_rules(&mut self, rules: &RenameAllRules) {
pub fn rename_by_rules(&mut self, rules: RenameAllRules) {
if !self.name.serialize_renamed {
self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize);
}
@@ -929,8 +990,8 @@ impl Variant {
}
}
pub fn rename_all_rules(&self) -> &RenameAllRules {
&self.rename_all_rules
pub fn rename_all_rules(&self) -> RenameAllRules {
self.rename_all_rules
}
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
@@ -1259,7 +1320,7 @@ impl Field {
self.name.deserialize_aliases()
}
pub fn rename_by_rules(&mut self, rules: &RenameAllRules) {
pub fn rename_by_rules(&mut self, rules: RenameAllRules) {
if !self.name.serialize_renamed {
self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize);
}
+12 -4
View File
@@ -54,8 +54,8 @@ impl RenameRule {
}
/// Apply a renaming rule to an enum variant, returning the version expected in the source.
pub fn apply_to_variant(&self, variant: &str) -> String {
match *self {
pub fn apply_to_variant(self, variant: &str) -> String {
match self {
None | PascalCase => variant.to_owned(),
LowerCase => variant.to_ascii_lowercase(),
UpperCase => variant.to_ascii_uppercase(),
@@ -79,8 +79,8 @@ impl RenameRule {
}
/// Apply a renaming rule to a struct field, returning the version expected in the source.
pub fn apply_to_field(&self, field: &str) -> String {
match *self {
pub fn apply_to_field(self, field: &str) -> String {
match self {
None | LowerCase | SnakeCase => field.to_owned(),
UpperCase => field.to_ascii_uppercase(),
PascalCase => {
@@ -107,6 +107,14 @@ impl RenameRule {
ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"),
}
}
/// Returns the `RenameRule` if it is not `None`, `rule_b` otherwise.
pub fn or(self, rule_b: Self) -> Self {
match self {
None => rule_b,
_ => self,
}
}
}
pub struct ParseError<'a> {
+1
View File
@@ -23,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 RENAME_ALL_FIELDS: Symbol = Symbol("rename_all_fields");
pub const REPR: Symbol = Symbol("repr");
pub const SERDE: Symbol = Symbol("serde");
pub const SERIALIZE: Symbol = Symbol("serialize");
+1 -2
View File
@@ -13,8 +13,7 @@
//!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.176")]
#![allow(unknown_lints, bare_trait_objects)]
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.177")]
// Ignored clippy lints
#![allow(
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
+1 -1
View File
@@ -1,5 +1,4 @@
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.28.0")]
#![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints
#![allow(
clippy::cognitive_complexity,
@@ -30,6 +29,7 @@
clippy::missing_errors_doc,
clippy::module_name_repetitions,
clippy::must_use_candidate,
clippy::return_self_not_must_use,
clippy::similar_names,
clippy::single_match_else,
clippy::struct_excessive_bools,
+14 -12
View File
@@ -2266,24 +2266,26 @@ fn test_internally_tagged_enum_with_skipped_conflict() {
#[serde(tag = "t")]
enum Data {
A,
#[serde(skip)]
B {
t: String
},
C {
#[serde(default, skip)]
t: String
},
#[serde(skip)]
#[allow(dead_code)]
B {
t: String,
},
C {
#[serde(default, skip)]
t: String,
},
}
let _data = Data::B { t: "".to_string() };
let data = Data::C { t: "".to_string() };
let data = Data::C { t: String::new() };
assert_tokens(
&data,
&[
Token::Struct { name: "Data", len: 1 },
Token::Struct {
name: "Data",
len: 1,
},
Token::Str("t"),
Token::Str("C"),
Token::StructEnd,
+56
View File
@@ -1923,6 +1923,62 @@ fn test_rename_all() {
);
}
#[test]
fn test_rename_all_fields() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all_fields = "kebab-case")]
enum E {
V1,
V2(bool),
V3 {
a_field: bool,
another_field: bool,
#[serde(rename = "last-field")]
yet_another_field: bool,
},
#[serde(rename_all = "snake_case")]
V4 {
a_field: bool,
},
}
assert_tokens(
&E::V3 {
a_field: true,
another_field: true,
yet_another_field: true,
},
&[
Token::StructVariant {
name: "E",
variant: "V3",
len: 3,
},
Token::Str("a-field"),
Token::Bool(true),
Token::Str("another-field"),
Token::Bool(true),
Token::Str("last-field"),
Token::Bool(true),
Token::StructVariantEnd,
],
);
assert_tokens(
&E::V4 { a_field: true },
&[
Token::StructVariant {
name: "E",
variant: "V4",
len: 1,
},
Token::Str("a_field"),
Token::Bool(true),
Token::StructVariantEnd,
],
);
}
#[test]
fn test_untagged_newtype_variant_containing_unit_struct_not_map() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
@@ -1,5 +1,5 @@
error: #[serde(default)] can only be used on structs with named fields
--> tests/ui/default-attribute/enum.rs:5:1
--> tests/ui/default-attribute/enum.rs:4:9
|
5 | enum E {
| ^^^^
4 | #[serde(default)]
| ^^^^^^^
@@ -1,5 +1,5 @@
error: #[serde(default = "...")] can only be used on structs with named fields
--> tests/ui/default-attribute/enum_path.rs:5:1
--> tests/ui/default-attribute/enum_path.rs:4:9
|
5 | enum E {
| ^^^^
4 | #[serde(default = "default_e")]
| ^^^^^^^^^^^^^^^^^^^^^
@@ -1,5 +1,5 @@
error: #[serde(default = "...")] can only be used on structs with named fields
--> tests/ui/default-attribute/nameless_struct_fields_path.rs:5:9
--> tests/ui/default-attribute/nameless_struct_fields_path.rs:4:9
|
5 | struct T(u8, u8);
| ^^^^^^^^
4 | #[serde(default = "default_t")]
| ^^^^^^^^^^^^^^^^^^^^^
@@ -1,5 +1,5 @@
error: #[serde(untagged)] can only be used on enums
--> tests/ui/enum-representation/untagged-struct.rs:5:1
--> tests/ui/enum-representation/untagged-struct.rs:4:9
|
5 | struct S;
| ^^^^^^
4 | #[serde(untagged)]
| ^^^^^^^^
@@ -1,5 +1,5 @@
error: #[serde(tag = "...")] can only be used on enums and structs with named fields
--> tests/ui/struct-representation/internally-tagged-tuple.rs:5:9
--> tests/ui/struct-representation/internally-tagged-tuple.rs:4:9
|
5 | struct S(u8, u8);
| ^^^^^^^^
4 | #[serde(tag = "type")]
| ^^^^^^^^^^^^
@@ -1,7 +1,5 @@
error: #[serde(tag = "...")] can only be used on enums and structs with named fields
--> tests/ui/struct-representation/internally-tagged-unit.rs:3:10
--> tests/ui/struct-representation/internally-tagged-unit.rs:4:9
|
3 | #[derive(Serialize)]
| ^^^^^^^^^
|
= note: this error originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info)
4 | #[serde(tag = "type")]
| ^^^^^^^^^^^^