diff --git a/.github/workflows/publish-crates-io.yaml b/.github/workflows/publish-crates-io.yaml index 24e32ce9..43ebc233 100644 --- a/.github/workflows/publish-crates-io.yaml +++ b/.github/workflows/publish-crates-io.yaml @@ -36,7 +36,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - # This pulls from the "Get Changelog Entry" step above, referencing it's ID to get its outputs object. + # This pulls from the "Get Changelog Entry" step above, referencing its ID to get its outputs object. # See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps tag_name: "v${{ steps.changelog_reader.outputs.version }}" name: "serde_with v${{ steps.changelog_reader.outputs.version }}" diff --git a/Cargo.toml b/Cargo.toml index 19872ab2..13c9218a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,26 @@ push = false shared-version = true sign-tag = true tag = false + +[workspace.lints.rust] +# unused_qualifications = "warn" + +[workspace.lints.clippy] +pedantic = { level = "warn", priority = -1 } +cast_possible_truncation = "allow" +cast_possible_wrap = "allow" +cast_precision_loss = "allow" +cast_sign_loss = "allow" +items_after_statements = "allow" +linkedlist = "allow" +match_same_arms = "allow" +match_wildcard_for_single_variants = "allow" +missing_errors_doc = "allow" +missing_panics_doc = "allow" +module_name_repetitions = "allow" +needless_pass_by_value = "allow" +needless_raw_string_hashes = "allow" +redundant_closure_for_method_calls = "allow" +similar_names = "allow" +too_many_lines = "allow" +wildcard_imports = "allow" diff --git a/serde_with/Cargo.toml b/serde_with/Cargo.toml index 005fc9b7..5db0f798 100644 --- a/serde_with/Cargo.toml +++ b/serde_with/Cargo.toml @@ -1,3 +1,5 @@ +lints.workspace = true + [package] authors = [ "Jonas Bushart", diff --git a/serde_with/src/base64.rs b/serde_with/src/base64.rs index 0e52e0c4..3c34cc8c 100644 --- a/serde_with/src/base64.rs +++ b/serde_with/src/base64.rs @@ -221,7 +221,7 @@ impl Alphabet for ImapMutf7 { } } -/// The character set used in BinHex 4.0 files. +/// The character set used in `BinHex` 4.0 files. /// /// See [BinHex 4.0 Definition](http://files.stairways.com/other/binhex-40-specs-info.txt). pub struct BinHex; diff --git a/serde_with/src/chrono_0_4.rs b/serde_with/src/chrono_0_4.rs index 28e41ca6..0504e657 100644 --- a/serde_with/src/chrono_0_4.rs +++ b/serde_with/src/chrono_0_4.rs @@ -191,7 +191,7 @@ impl<'de> DeserializeAs<'de, NaiveDateTime> for DateTime { } } -/// Convert a [`chrono_0_4::Duration`] into a [`DurationSigned`] +/// Convert a [`Duration`] into a [`DurationSigned`] fn duration_into_duration_signed(dur: &Duration) -> DurationSigned { match dur.to_std() { Ok(dur) => DurationSigned::with_duration(Sign::Positive, dur), @@ -205,7 +205,7 @@ fn duration_into_duration_signed(dur: &Duration) -> DurationSigned { } } -/// Convert a [`DurationSigned`] into a [`chrono_0_4::Duration`] +/// Convert a [`DurationSigned`] into a [`Duration`] fn duration_from_duration_signed<'de, D>(dur: DurationSigned) -> Result where D: Deserializer<'de>, diff --git a/serde_with/src/content/de.rs b/serde_with/src/content/de.rs index e6bbf518..a1b9efb9 100644 --- a/serde_with/src/content/de.rs +++ b/serde_with/src/content/de.rs @@ -62,17 +62,17 @@ impl<'de> Content<'de> { fn unexpected(&self) -> Unexpected<'_> { match *self { Content::Bool(b) => Unexpected::Bool(b), - Content::U8(n) => Unexpected::Unsigned(n as u64), - Content::U16(n) => Unexpected::Unsigned(n as u64), - Content::U32(n) => Unexpected::Unsigned(n as u64), + Content::U8(n) => Unexpected::Unsigned(u64::from(n)), + Content::U16(n) => Unexpected::Unsigned(u64::from(n)), + Content::U32(n) => Unexpected::Unsigned(u64::from(n)), Content::U64(n) => Unexpected::Unsigned(n), Content::U128(_) => Unexpected::Other("u128"), - Content::I8(n) => Unexpected::Signed(n as i64), - Content::I16(n) => Unexpected::Signed(n as i64), - Content::I32(n) => Unexpected::Signed(n as i64), + Content::I8(n) => Unexpected::Signed(i64::from(n)), + Content::I16(n) => Unexpected::Signed(i64::from(n)), + Content::I32(n) => Unexpected::Signed(i64::from(n)), Content::I64(n) => Unexpected::Signed(n), Content::I128(_) => Unexpected::Other("i128"), - Content::F32(f) => Unexpected::Float(f as f64), + Content::F32(f) => Unexpected::Float(f64::from(f)), Content::F64(f) => Unexpected::Float(f), Content::Char(c) => Unexpected::Char(c), Content::String(ref s) => Unexpected::Str(s), @@ -765,7 +765,7 @@ where } (variant, Some(value)) } - s @ Content::String(_) | s @ Content::Str(_) => (s, None), + s @ (Content::String(_) | Content::Str(_)) => (s, None), other => { return Err(DeError::invalid_type(other.unexpected(), &"string or map")); } @@ -1540,7 +1540,7 @@ where } (variant, Some(value)) } - ref s @ Content::String(_) | ref s @ Content::Str(_) => (s, None), + ref s @ (Content::String(_) | Content::Str(_)) => (s, None), ref other => { return Err(DeError::invalid_type(other.unexpected(), &"string or map")); } diff --git a/serde_with/src/de/impls.rs b/serde_with/src/de/impls.rs index ed25d9d3..8758b3d7 100644 --- a/serde_with/src/de/impls.rs +++ b/serde_with/src/de/impls.rs @@ -1578,8 +1578,7 @@ where Err(err) => err, }; Err(DeError::custom(format_args!( - "OneOrMany could not deserialize any variant:\n One: {}\n Many: {}", - one_err, many_err + "OneOrMany could not deserialize any variant:\n One: {one_err}\n Many: {many_err}", ))) } } @@ -1623,8 +1622,7 @@ where Err(err) => err, }; Err(DeError::custom(format_args!( - "PickFirst could not deserialize any variant:\n First: {}\n Second: {}", - first_err, second_err + "PickFirst could not deserialize any variant:\n First: {first_err}\n Second: {second_err}", ))) } } @@ -1662,8 +1660,7 @@ where Err(err) => err, }; Err(DeError::custom(format_args!( - "PickFirst could not deserialize any variant:\n First: {}\n Second: {}\n Third: {}", - first_err, second_err, third_err, + "PickFirst could not deserialize any variant:\n First: {first_err}\n Second: {second_err}\n Third: {third_err}", ))) } } @@ -1708,8 +1705,7 @@ where Err(err) => err, }; Err(DeError::custom(format_args!( - "PickFirst could not deserialize any variant:\n First: {}\n Second: {}\n Third: {}\n Fourth: {}", - first_err, second_err, third_err, fourth_err, + "PickFirst could not deserialize any variant:\n First: {first_err}\n Second: {second_err}\n Third: {third_err}\n Fourth: {fourth_err}", ))) } } @@ -1854,7 +1850,7 @@ impl<'de> DeserializeAs<'de, bool> for BoolFromInt { 0 => Ok(false), 1 => Ok(true), unexp => Err(DeError::invalid_value( - Unexpected::Unsigned(unexp as u64), + Unexpected::Unsigned(u64::from(unexp)), &"0 or 1", )), } @@ -1868,7 +1864,7 @@ impl<'de> DeserializeAs<'de, bool> for BoolFromInt { 0 => Ok(false), 1 => Ok(true), unexp => Err(DeError::invalid_value( - Unexpected::Signed(unexp as i64), + Unexpected::Signed(i64::from(unexp)), &"0 or 1", )), } diff --git a/serde_with/src/enum_map.rs b/serde_with/src/enum_map.rs index bc6f1378..cc533bda 100644 --- a/serde_with/src/enum_map.rs +++ b/serde_with/src/enum_map.rs @@ -737,7 +737,7 @@ where self.deserialize_seq(visitor) } - serde::forward_to_deserialize_any! { + forward_to_deserialize_any! { bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct tuple tuple_struct map struct enum identifier ignored_any @@ -819,7 +819,7 @@ where visitor.visit_enum(self) } - serde::forward_to_deserialize_any! { + forward_to_deserialize_any! { bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map struct identifier ignored_any diff --git a/serde_with/src/guide.md b/serde_with/src/guide.md index 788d4c92..c55cdef9 100644 --- a/serde_with/src/guide.md +++ b/serde_with/src/guide.md @@ -11,7 +11,7 @@ The crate offers four types of functionality. ## 1. A more flexible and composable replacement for the with annotation, called `serde_as` This is an alternative to [serde's with-annotation][with-annotation], which adds flexibility and composability to the scheme. -The main downside is that it work with fewer types than [with-annotations][with-annotation]. +The main downside is that it works with fewer types than [with-annotations][with-annotation]. However, all types from the Rust Standard Library should be supported in all combinations and any missing entry is a bug. You mirror the type structure of the field you want to de/serialize. diff --git a/serde_with/src/rust.rs b/serde_with/src/rust.rs index acfca714..165ff936 100644 --- a/serde_with/src/rust.rs +++ b/serde_with/src/rust.rs @@ -178,7 +178,7 @@ pub mod unwrap_or_skip { /// /// The implementation supports both the [`HashSet`] and the [`BTreeSet`] from the standard library. /// -/// # Converting to serde_as +/// # Converting to `serde_as` /// /// The same functionality can be more clearly expressed using the `serde_as` macro and [`SetPreventDuplicates`]. /// The `_` is a placeholder which works for any type which implements [`Serialize`]/[`Deserialize`]. @@ -294,7 +294,7 @@ pub mod sets_duplicate_value_is_error { /// /// The implementation supports both the [`HashMap`] and the [`BTreeMap`] from the standard library. /// -/// # Converting to serde_as +/// # Converting to `serde_as` /// /// The same functionality can be more clearly expressed using the `serde_as` macro and [`MapPreventDuplicates`]. /// The `_` is a placeholder which works for any type which implements [`Serialize`]/[`Deserialize`]. @@ -414,7 +414,7 @@ pub mod maps_duplicate_key_is_error { /// /// The implementation supports both the [`HashSet`] and the [`BTreeSet`] from the standard library. /// -/// # Converting to serde_as +/// # Converting to `serde_as` /// /// The same functionality can be more clearly expressed using the `serde_as` macro and [`SetLastValueWins`]. /// The `_` is a placeholder which works for any type which implements [`Serialize`]/[`Deserialize`]. @@ -502,7 +502,7 @@ pub mod sets_last_value_wins { /// [`HashMap`]: std::collections::HashMap /// [`BTreeMap`]: std::collections::HashMap /// -/// # Converting to serde_as +/// # Converting to `serde_as` /// /// The same functionality can be more clearly expressed using the `serde_as` macro and [`MapFirstKeyWins`]. /// The `_` is a placeholder which works for any type which implements [`Serialize`]/[`Deserialize`]. diff --git a/serde_with/src/ser/impls.rs b/serde_with/src/ser/impls.rs index dae073ed..88e18160 100644 --- a/serde_with/src/ser/impls.rs +++ b/serde_with/src/ser/impls.rs @@ -972,7 +972,7 @@ impl SerializeAs for BoolFromInt { where S: Serializer, { - serializer.serialize_u8(*source as u8) + serializer.serialize_u8(u8::from(*source)) } } diff --git a/serde_with/src/utils.rs b/serde_with/src/utils.rs index 77baec4e..a2ce090f 100644 --- a/serde_with/src/utils.rs +++ b/serde_with/src/utils.rs @@ -114,30 +114,30 @@ where } pub(crate) fn duration_as_secs_f64(dur: &Duration) -> f64 { - (dur.as_secs() as f64) + (dur.subsec_nanos() as f64) / (NANOS_PER_SEC as f64) + (dur.as_secs() as f64) + f64::from(dur.subsec_nanos()) / f64::from(NANOS_PER_SEC) } pub(crate) fn duration_signed_from_secs_f64(secs: f64) -> Result { - const MAX_NANOS_F64: f64 = ((u64::max_value() as u128 + 1) * (NANOS_PER_SEC as u128)) as f64; + const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64; // TODO why are the seconds converted to nanoseconds first? // Does it make sense to just truncate the value? - let mut nanos = secs * (NANOS_PER_SEC as f64); + let mut nanos = secs * (f64::from(NANOS_PER_SEC)); if !nanos.is_finite() { return Err("got non-finite value when converting float to duration"); } if nanos >= MAX_NANOS_F64 { return Err("overflow when converting float to duration"); } - let mut sign = self::duration::Sign::Positive; + let mut sign = Sign::Positive; if nanos < 0.0 { nanos = -nanos; - sign = self::duration::Sign::Negative; + sign = Sign::Negative; } let nanos = nanos as u128; - Ok(self::duration::DurationSigned::new( + Ok(DurationSigned::new( sign, - (nanos / (NANOS_PER_SEC as u128)) as u64, - (nanos % (NANOS_PER_SEC as u128)) as u32, + (nanos / u128::from(NANOS_PER_SEC)) as u64, + (nanos % u128::from(NANOS_PER_SEC)) as u32, )) } diff --git a/serde_with/src/utils/duration.rs b/serde_with/src/utils/duration.rs index a0607b18..7c2d4764 100644 --- a/serde_with/src/utils/duration.rs +++ b/serde_with/src/utils/duration.rs @@ -14,26 +14,36 @@ pub(crate) enum Sign { impl Sign { #[allow(dead_code)] - pub(crate) fn is_positive(&self) -> bool { - *self == Sign::Positive + pub(crate) fn is_positive(self) -> bool { + self == Sign::Positive } #[allow(dead_code)] - pub(crate) fn is_negative(&self) -> bool { - *self == Sign::Negative + pub(crate) fn is_negative(self) -> bool { + self == Sign::Negative } - pub(crate) fn apply(&self, value: T) -> T + pub(crate) fn apply(self, value: T) -> T where T: core::ops::Neg, { - match *self { + match self { Sign::Positive => value, Sign::Negative => value.neg(), } } } +impl From for Sign { + fn from(value: i64) -> Self { + if value.is_negative() { + Sign::Negative + } else { + Sign::Positive + } + } +} + #[derive(Copy, Clone)] pub(crate) struct DurationSigned { pub(crate) sign: Sign, @@ -356,13 +366,8 @@ impl<'de> DeserializeAs<'de, DurationSigned> for DurationSeconds { where D: Deserializer<'de>, { - i64::deserialize(deserializer).map(|secs: i64| { - let sign = match secs.is_negative() { - true => Sign::Negative, - false => Sign::Positive, - }; - DurationSigned::new(sign, secs.abs_diff(0), 0) - }) + i64::deserialize(deserializer) + .map(|secs: i64| DurationSigned::new(secs.into(), secs.abs_diff(0), 0)) } } @@ -398,11 +403,7 @@ impl<'de> DeserializeAs<'de, DurationSigned> for DurationSeconds E: DeError, { let secs: i64 = value.parse().map_err(DeError::custom)?; - let sign = match secs.is_negative() { - true => Sign::Negative, - false => Sign::Positive, - }; - Ok(DurationSigned::new(sign, secs.abs_diff(0), 0)) + Ok(DurationSigned::new(secs.into(), secs.abs_diff(0), 0)) } } @@ -543,7 +544,7 @@ fn test_parse_float_into_time_parts() { parse_float_into_time_parts("-123.000987") ); assert_eq!( - Ok((Sign::Positive, 18446744073709551615, 123_456_789)), + Ok((Sign::Positive, 18_446_744_073_709_551_615, 123_456_789)), parse_float_into_time_parts("18446744073709551615.123456789") ); diff --git a/serde_with/src/with_prefix.rs b/serde_with/src/with_prefix.rs index f5a5d41f..b8e7a4e0 100644 --- a/serde_with/src/with_prefix.rs +++ b/serde_with/src/with_prefix.rs @@ -218,8 +218,8 @@ where } fn serialize_str(self, v: &str) -> Result { - self.delegate - .collect_str(&format_args!("{}{}", self.prefix, v)) + let prefix = self.prefix; + self.delegate.collect_str(&format_args!("{prefix}{v}")) } fn serialize_bytes(self, _v: &[u8]) -> Result { diff --git a/serde_with/tests/hashbrown_0_14.rs b/serde_with/tests/hashbrown_0_14.rs index 9698e398..4b6481b0 100644 --- a/serde_with/tests/hashbrown_0_14.rs +++ b/serde_with/tests/hashbrown_0_14.rs @@ -26,7 +26,7 @@ fn test_hashmap() { // Normal is_equal( - S([(1, 1), (3, 3), (111, 111)].iter().cloned().collect()), + S([(1, 1), (3, 3), (111, 111)].iter().copied().collect()), expect![[r#" { "1": "1", @@ -47,7 +47,7 @@ fn test_hashmap() { // Normal is_equal( - SStd([(1, 1)].iter().cloned().collect()), + SStd([(1, 1)].iter().copied().collect()), expect![[r#" { "1": "1" @@ -64,7 +64,7 @@ fn test_hashset() { // Normal is_equal( - S([1, 2, 3, 4, 5].iter().cloned().collect()), + S([1, 2, 3, 4, 5].iter().copied().collect()), expect![[r#" [ "5", @@ -87,7 +87,7 @@ fn test_hashset() { // Normal is_equal( - SStd([1].iter().cloned().collect()), + SStd([1].iter().copied().collect()), expect![[r#" [ "1" @@ -236,7 +236,7 @@ fn duplicate_value_last_wins_hashset() { where H: std::hash::Hasher, { - self.0.hash(state) + self.0.hash(state); } } diff --git a/serde_with/tests/indexmap_1.rs b/serde_with/tests/indexmap_1.rs index 0f53bb3b..adc2050c 100644 --- a/serde_with/tests/indexmap_1.rs +++ b/serde_with/tests/indexmap_1.rs @@ -24,7 +24,7 @@ fn test_indexmap() { // Normal is_equal( - S([(1, 1), (3, 3), (111, 111)].iter().cloned().collect()), + S([(1, 1), (3, 3), (111, 111)].iter().copied().collect()), expect![[r#" { "1": "1", @@ -43,7 +43,7 @@ fn test_indexset() { // Normal is_equal( - S([1, 2, 3, 4, 5].iter().cloned().collect()), + S([1, 2, 3, 4, 5].iter().copied().collect()), expect![[r#" [ "1", @@ -196,7 +196,7 @@ fn duplicate_value_last_wins_indexset() { where H: std::hash::Hasher, { - self.0.hash(state) + self.0.hash(state); } } diff --git a/serde_with/tests/indexmap_2.rs b/serde_with/tests/indexmap_2.rs index 58a12b3d..17c0fcb8 100644 --- a/serde_with/tests/indexmap_2.rs +++ b/serde_with/tests/indexmap_2.rs @@ -24,7 +24,7 @@ fn test_indexmap() { // Normal is_equal( - S([(1, 1), (3, 3), (111, 111)].iter().cloned().collect()), + S([(1, 1), (3, 3), (111, 111)].iter().copied().collect()), expect![[r#" { "1": "1", @@ -43,7 +43,7 @@ fn test_indexset() { // Normal is_equal( - S([1, 2, 3, 4, 5].iter().cloned().collect()), + S([1, 2, 3, 4, 5].iter().copied().collect()), expect![[r#" [ "1", @@ -196,7 +196,7 @@ fn duplicate_value_last_wins_indexset() { where H: std::hash::Hasher, { - self.0.hash(state) + self.0.hash(state); } } diff --git a/serde_with/tests/rust.rs b/serde_with/tests/rust.rs index 9b3efeff..8dfa91cb 100644 --- a/serde_with/tests/rust.rs +++ b/serde_with/tests/rust.rs @@ -218,7 +218,7 @@ fn duplicate_value_first_wins_hashset() { where H: std::hash::Hasher, { - self.0.hash(state) + self.0.hash(state); } } @@ -279,7 +279,7 @@ fn duplicate_value_last_wins_hashset() { where H: std::hash::Hasher, { - self.0.hash(state) + self.0.hash(state); } } diff --git a/serde_with/tests/serde_as/collections.rs b/serde_with/tests/serde_as/collections.rs index dad84c49..2dcc7c1b 100644 --- a/serde_with/tests/serde_as/collections.rs +++ b/serde_with/tests/serde_as/collections.rs @@ -1,7 +1,7 @@ use super::*; use fnv::{FnvHashMap, FnvHashSet}; -/// Test that HashSets are also supported with non-default hashers. +/// Test that `HashSets` are also supported with non-default hashers. #[test] fn test_fnv_hashset() { #[serde_as] @@ -10,7 +10,7 @@ fn test_fnv_hashset() { // Normal is_equal( - S([1, 2, 3, 4, 5].iter().cloned().collect()), + S([1, 2, 3, 4, 5].iter().copied().collect()), expect![[r#" [ "5", @@ -23,7 +23,7 @@ fn test_fnv_hashset() { is_equal(S(FnvHashSet::default()), expect![[r#"[]"#]]); } -/// Test that HashSets are also supported with non-default hashers. +/// Test that `HashSets` are also supported with non-default hashers. #[test] fn test_fnv_hashmap() { #[serde_as] @@ -32,7 +32,7 @@ fn test_fnv_hashmap() { // Normal is_equal( - S([(1, 1), (3, 3), (111, 111)].iter().cloned().collect()), + S([(1, 1), (3, 3), (111, 111)].iter().copied().collect()), expect![[r#" { "1": "1", @@ -40,5 +40,5 @@ fn test_fnv_hashmap() { "111": "111" }"#]], ); - is_equal(S(FnvHashMap::default()), expect![[r#"{}"#]]); + is_equal(S(FnvHashMap::default()), expect![[r"{}"]]); } diff --git a/serde_with/tests/serde_as/lib.rs b/serde_with/tests/serde_as/lib.rs index b7c96ee0..1c5416b3 100644 --- a/serde_with/tests/serde_as/lib.rs +++ b/serde_with/tests/serde_as/lib.rs @@ -510,7 +510,7 @@ fn string_with_separator() { let x = A { tags: vec!["1".to_string(), "2".to_string(), "3".to_string()], - more_tags: Default::default(), + more_tags: BTreeSet::default(), }; assert_eq!( r#"{"tags":"1 2 3","more_tags":""}"#, @@ -737,6 +737,7 @@ fn test_big_arrays() { } #[test] +#[allow(clippy::ref_option_ref)] fn test_bytes() { // The test case is copied from // https://github.com/serde-rs/bytes/blob/cbae606b9dc225fc094b031cc84eac9493da2058/tests/test_derive.rs diff --git a/serde_with/tests/serde_as/serde_as_macro.rs b/serde_with/tests/serde_as/serde_as_macro.rs index 4799ac06..80785ce8 100644 --- a/serde_with/tests/serde_as/serde_as_macro.rs +++ b/serde_with/tests/serde_as/serde_as_macro.rs @@ -242,6 +242,7 @@ fn test_default_on_option() { expect!["missing field `a` at line 1 column 2"], ); + #[allow(clippy::unnecessary_wraps)] fn default_555() -> Option { Some(555) } diff --git a/serde_with/tests/utils.rs b/serde_with/tests/utils.rs index d9247fff..e4995eb0 100644 --- a/serde_with/tests/utils.rs +++ b/serde_with/tests/utils.rs @@ -75,5 +75,5 @@ where &serde_json::from_str::(deserialize_from) .unwrap_err() .to_string(), - ) + ); } diff --git a/serde_with/tests/version_numbers.rs b/serde_with/tests/version_numbers.rs index d9cdc2fd..ced72051 100644 --- a/serde_with/tests/version_numbers.rs +++ b/serde_with/tests/version_numbers.rs @@ -30,7 +30,7 @@ fn test_serde_with_macros_dependency() { /// The `*` version specifier is not allowed. /// /// Arguably this should be part of version-sync. There is an open issue for this feature: -/// https://github.com/mgeisler/version-sync/issues/72 +/// #[test] fn test_docs_rs_url_point_to_current_version() -> Result<(), Box> { let pkg_name = env!("CARGO_PKG_NAME"); @@ -60,7 +60,7 @@ fn test_docs_rs_url_point_to_current_version() -> Result<(), Box {} } diff --git a/serde_with/tests/with_prefix.rs b/serde_with/tests/with_prefix.rs index bc7a7871..47671532 100644 --- a/serde_with/tests/with_prefix.rs +++ b/serde_with/tests/with_prefix.rs @@ -127,7 +127,7 @@ fn test_plain_with_prefix() { ); } -/// Ensure that with_prefix works for unit type enum variants. +/// Ensure that `with_prefix` works for unit type enum variants. #[test] fn test_enum_unit_variant_with_prefix() { #[derive(Hash, PartialEq, Eq, Debug, Serialize, Deserialize, Ord, PartialOrd)] diff --git a/serde_with_macros/Cargo.toml b/serde_with_macros/Cargo.toml index 95b967c5..e8e4ccc8 100644 --- a/serde_with_macros/Cargo.toml +++ b/serde_with_macros/Cargo.toml @@ -1,3 +1,5 @@ +lints.workspace = true + [package] authors = ["Jonas Bushart"] name = "serde_with_macros" diff --git a/serde_with_macros/src/apply.rs b/serde_with_macros/src/apply.rs index 43ecc1d8..d6c1ec59 100644 --- a/serde_with_macros/src/apply.rs +++ b/serde_with_macros/src/apply.rs @@ -59,14 +59,14 @@ impl Parse for ApplyInput { } pub fn apply(args: TokenStream, input: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as ApplyInput); - #[derive(FromMeta)] struct SerdeContainerOptions { #[darling(rename = "crate")] alt_crate_path: Option, } + let args = syn::parse_macro_input!(args as ApplyInput); + let container_options = match SerdeContainerOptions::from_list(&args.metas) { Ok(v) => v, Err(e) => { @@ -77,14 +77,12 @@ pub fn apply(args: TokenStream, input: TokenStream) -> TokenStream { .alt_crate_path .unwrap_or_else(|| syn::parse_quote!(::serde_with)); - let res = match super::apply_function_to_struct_and_enum_fields_darling( + let res = super::apply_function_to_struct_and_enum_fields_darling( input, &serde_with_crate_path, &prepare_apply_attribute_to_field(args), - ) { - Ok(res) => res, - Err(err) => err.write_errors(), - }; + ) + .unwrap_or_else(|err| err.write_errors()); TokenStream::from(res) } @@ -101,7 +99,7 @@ fn prepare_apply_attribute_to_field( return Ok(()); } - for matcher in input.rules.iter() { + for matcher in &input.rules { if ty_pattern_matches_ty(&matcher.ty, &field.ty) { field.attrs.extend(matcher.attrs.clone()); } @@ -160,7 +158,7 @@ fn ty_pattern_matches_ty(ty_pattern: &Type, ty: &Type) -> bool { /// /// Two paths match if they are equal except for the path arguments. /// Path arguments are generics on types or functions. - /// If the pattern has no argument, it can match with everthing. + /// If the pattern has no argument, it can match with everything. /// If the pattern does have an argument, the other side must be equal. fn path_pattern_matches_path(path_pattern: &Path, path: &Path) -> bool { if path_pattern.leading_colon != path.leading_colon @@ -168,7 +166,7 @@ fn ty_pattern_matches_ty(ty_pattern: &Type, ty: &Type) -> bool { { return false; } - // Boths parts are equal length + // Both parts are equal length std::iter::zip(&path_pattern.segments, &path.segments).all( |(path_pattern_segment, path_segment)| { let ident_equal = path_pattern_segment.ident == path_segment.ident; diff --git a/serde_with_macros/src/lib.rs b/serde_with_macros/src/lib.rs index 0d1218fb..d6362286 100644 --- a/serde_with_macros/src/lib.rs +++ b/serde_with_macros/src/lib.rs @@ -115,7 +115,7 @@ where } } -/// Like [apply_function_to_struct_and_enum_fields] but for darling errors +/// Like [`apply_function_to_struct_and_enum_fields`] but for darling errors fn apply_function_to_struct_and_enum_fields_darling( input: TokenStream, serde_with_crate_path: &Path, @@ -317,17 +317,13 @@ where /// ``` #[proc_macro_attribute] pub fn skip_serializing_none(_args: TokenStream, input: TokenStream) -> TokenStream { - let res = match apply_function_to_struct_and_enum_fields( - input, - skip_serializing_none_add_attr_to_field, - ) { - Ok(res) => res, - Err(err) => err.to_compile_error(), - }; + let res = + apply_function_to_struct_and_enum_fields(input, skip_serializing_none_add_attr_to_field) + .unwrap_or_else(|err| err.to_compile_error()); TokenStream::from(res) } -/// Add the skip_serializing_if annotation to each field of the struct +/// Add the `skip_serializing_if` annotation to each field of the struct fn skip_serializing_none_add_attr_to_field(field: &mut Field) -> Result<(), String> { if is_std_option(&field.ty) { let has_skip_serializing_if = field_has_attribute(field, "serde", "skip_serializing_if"); @@ -423,8 +419,8 @@ fn is_std_option(type_: &Type) -> bool { /// `#[serde(skip_serializing_if = "Option::is_none")]` /// /// * `serde` is the outermost path, here namespace -/// * it contains a Meta::List -/// * which contains in another Meta a Meta::NameValue +/// * it contains a `Meta::List` +/// * which contains in another Meta a `Meta::NameValue` /// * with the name being `skip_serializing_if` fn field_has_attribute(field: &Field, namespace: &str, name: &str) -> bool { for attr in &field.attrs { @@ -453,7 +449,7 @@ fn field_has_attribute(field: &Field, namespace: &str, name: &str) -> bool { } } } - _ => (), + Meta::List(_) => (), } } } @@ -614,14 +610,12 @@ pub fn serde_as(args: TokenStream, input: TokenStream) -> TokenStream { .unwrap_or_else(|| syn::parse_quote!(::serde_with)); // Convert any error message into a nice compiler error - let res = match apply_function_to_struct_and_enum_fields_darling( + let res = apply_function_to_struct_and_enum_fields_darling( input, &serde_with_crate_path, |field| serde_as_add_attr_to_field(field, &serde_with_crate_path), - ) { - Ok(res) => res, - Err(err) => err.write_errors(), - }; + ) + .unwrap_or_else(|err| err.write_errors()); TokenStream::from(res) } Err(e) => TokenStream::from(DarlingError::from(e).write_errors()), @@ -780,7 +774,7 @@ fn serde_as_add_attr_to_field( /// Recursively replace all occurrences of `_` with `replacement` in a [Type][] /// -/// The [serde_as][macro@serde_as] macro allows to use the infer type, i.e., `_`, as shortcut for +/// The [`serde_as`][macro@serde_as] macro allows to use the infer type, i.e., `_`, as shortcut for /// `serde_with::As`. This function replaces all occurrences of the infer type with another type. fn replace_infer_type_with_type(to_replace: Type, replacement: &Type) -> Type { match to_replace { @@ -804,45 +798,42 @@ fn replace_infer_type_with_type(to_replace: Type, replacement: &Type) -> Type { Type::Paren(inner) } Type::Path(mut inner) => { - match inner.path.segments.pop() { - Some(Pair::End(mut t)) | Some(Pair::Punctuated(mut t, _)) => { - t.arguments = match t.arguments { - PathArguments::None => PathArguments::None, - PathArguments::AngleBracketed(mut inner) => { - // Iterate over the args between the angle brackets - inner.args = inner - .args - .into_iter() - .map(|generic_argument| match generic_argument { - // replace types within the generics list, but leave other stuff - // like lifetimes untouched - GenericArgument::Type(type_) => GenericArgument::Type( - replace_infer_type_with_type(type_, replacement), - ), - ga => ga, - }) - .collect(); - PathArguments::AngleBracketed(inner) - } - PathArguments::Parenthesized(mut inner) => { - inner.inputs = inner - .inputs - .into_iter() - .map(|type_| replace_infer_type_with_type(type_, replacement)) - .collect(); - inner.output = match inner.output { - ReturnType::Type(arrow, mut type_) => { - *type_ = replace_infer_type_with_type(*type_, replacement); - ReturnType::Type(arrow, type_) - } - default => default, - }; - PathArguments::Parenthesized(inner) - } - }; - inner.path.segments.push(t); - } - None => {} + if let Some(Pair::End(mut t) | Pair::Punctuated(mut t, _)) = inner.path.segments.pop() { + t.arguments = match t.arguments { + PathArguments::None => PathArguments::None, + PathArguments::AngleBracketed(mut inner) => { + // Iterate over the args between the angle brackets + inner.args = inner + .args + .into_iter() + .map(|generic_argument| match generic_argument { + // replace types within the generics list, but leave other stuff + // like lifetimes untouched + GenericArgument::Type(type_) => GenericArgument::Type( + replace_infer_type_with_type(type_, replacement), + ), + ga => ga, + }) + .collect(); + PathArguments::AngleBracketed(inner) + } + PathArguments::Parenthesized(mut inner) => { + inner.inputs = inner + .inputs + .into_iter() + .map(|type_| replace_infer_type_with_type(type_, replacement)) + .collect(); + inner.output = match inner.output { + ReturnType::Type(arrow, mut type_) => { + *type_ = replace_infer_type_with_type(*type_, replacement); + ReturnType::Type(arrow, type_) + } + default => default, + }; + PathArguments::Parenthesized(inner) + } + }; + inner.path.segments.push(t); } Type::Path(inner) } @@ -1021,11 +1012,11 @@ pub fn derive_deserialize_fromstr(item: TokenStream) -> TokenStream { }; TokenStream::from(deserialize_fromstr( input, - derive_options.get_serde_with_path(), + &derive_options.get_serde_with_path(), )) } -fn deserialize_fromstr(mut input: DeriveInput, serde_with_crate_path: Path) -> TokenStream2 { +fn deserialize_fromstr(mut input: DeriveInput, serde_with_crate_path: &Path) -> TokenStream2 { let ident = input.ident; let where_clause = &mut input.generics.make_where_clause().predicates; where_clause.push(parse_quote!(Self: #serde_with_crate_path::__private__::FromStr)); @@ -1141,11 +1132,11 @@ pub fn derive_serialize_display(item: TokenStream) -> TokenStream { }; TokenStream::from(serialize_display( input, - derive_options.get_serde_with_path(), + &derive_options.get_serde_with_path(), )) } -fn serialize_display(mut input: DeriveInput, serde_with_crate_path: Path) -> TokenStream2 { +fn serialize_display(mut input: DeriveInput, serde_with_crate_path: &Path) -> TokenStream2 { let ident = input.ident; input .generics diff --git a/serde_with_macros/tests/serde_as_issue_538.rs b/serde_with_macros/tests/serde_as_issue_538.rs index 2ac2f08c..bcbbad97 100644 --- a/serde_with_macros/tests/serde_as_issue_538.rs +++ b/serde_with_macros/tests/serde_as_issue_538.rs @@ -1,7 +1,7 @@ -//! Check for the correct processing of ExprGroups in types +//! Check for the correct processing of `ExprGroups` in types //! -//! They occur when the types is passed in as a macro_rules argument like here. -//! https://github.com/jonasbb/serde_with/issues/538 +//! They occur when the types is passed in as a `macro_rules` argument like here. +//! macro_rules! t { ($($param:ident : $ty:ty),*) => { @@ -24,7 +24,7 @@ t!(d: Option); #[test] fn t() { - let expected = r#"{}"#; - let data: Data = Default::default(); + let expected = "{}"; + let data = Data::default(); assert_eq!(expected, serde_json::to_string(&data).unwrap()); } diff --git a/serde_with_test/Cargo.toml b/serde_with_test/Cargo.toml index ceaf59d9..6ea2320d 100644 --- a/serde_with_test/Cargo.toml +++ b/serde_with_test/Cargo.toml @@ -1,3 +1,5 @@ +lints.workspace = true + [package] name = "serde_with_test" publish = false diff --git a/serde_with_test/tests/flattened_maybe.rs b/serde_with_test/tests/flattened_maybe.rs index 3b189754..4d729d9c 100644 --- a/serde_with_test/tests/flattened_maybe.rs +++ b/serde_with_test/tests/flattened_maybe.rs @@ -1,4 +1,4 @@ -//! Test that flattened_maybe properly names all the types and traits used +//! Test that `flattened_maybe` properly names all the types and traits used // Ensure no prelude is available #![no_implicit_prelude] diff --git a/serde_with_test/tests/serde_as_cfg.rs b/serde_with_test/tests/serde_as_cfg.rs index f4d88aff..72347a87 100644 --- a/serde_with_test/tests/serde_as_cfg.rs +++ b/serde_with_test/tests/serde_as_cfg.rs @@ -1,4 +1,4 @@ -//! Test that cfg_eval helps in cfg-gating serde_with attributes +//! Test that `cfg_eval` helps in cfg-gating `serde_with` attributes // Ensure no prelude is available #![no_implicit_prelude] diff --git a/serde_with_test/tests/serde_conv.rs b/serde_with_test/tests/serde_conv.rs index 0a9ce86b..a1ddbcba 100644 --- a/serde_with_test/tests/serde_conv.rs +++ b/serde_with_test/tests/serde_conv.rs @@ -1,8 +1,9 @@ -//! Test that the serde_conv macros properly name all the types and traits used +//! Test that the `serde_conv` macros properly name all the types and traits used // Ensure no prelude is available #![no_implicit_prelude] #![allow(dead_code, unused_imports)] +#![allow(clippy::trivially_copy_pass_by_ref)] use ::s_with::serde_conv; diff --git a/serde_with_test/tests/with_prefix.rs b/serde_with_test/tests/with_prefix.rs index e3ca7c08..cfb117ed 100644 --- a/serde_with_test/tests/with_prefix.rs +++ b/serde_with_test/tests/with_prefix.rs @@ -1,4 +1,4 @@ -//! Test that the with_prefix macros properly name all the types and traits used +//! Test that the `with_prefix` macros properly name all the types and traits used // Ensure no prelude is available #![no_implicit_prelude]