From 56da8eeb3a12917ab03c62fa5c91cb9f09cdcfc8 Mon Sep 17 00:00:00 2001 From: Tommy Jensen <1867375+grindvoll@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:08:17 +0200 Subject: [PATCH 1/5] Fixes #511: Allow deserialize_string for map fields originating from struct-formatted maps --- src/de/id.rs | 4 +- tests/511_deserialize_any_map_string_key.rs | 51 +++++++++++++++++++++ tests/non_identifier_identifier.rs | 6 ++- 3 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 tests/511_deserialize_any_map_string_key.rs diff --git a/src/de/id.rs b/src/de/id.rs index 069cabb8e..1136e5187 100644 --- a/src/de/id.rs +++ b/src/de/id.rs @@ -144,11 +144,11 @@ impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut Deserializer<'a, 'b> { Err(Error::ExpectedIdentifier) } - fn deserialize_string(self, _: V) -> Result + fn deserialize_string(self, visitor: V) -> Result where V: Visitor<'b>, { - Err(Error::ExpectedIdentifier) + self.deserialize_identifier(visitor) } fn deserialize_bytes(self, _: V) -> Result diff --git a/tests/511_deserialize_any_map_string_key.rs b/tests/511_deserialize_any_map_string_key.rs new file mode 100644 index 000000000..5e12966aa --- /dev/null +++ b/tests/511_deserialize_any_map_string_key.rs @@ -0,0 +1,51 @@ +#[test] +fn test_map_custom_deserialize() { + use std::collections::HashMap; + + #[derive(PartialEq, Debug)] + struct CustomMap(HashMap); + + // Use a custom deserializer for CustomMap in order to extract String + // keys in the visit_map method. + impl<'de> serde::de::Deserialize<'de> for CustomMap { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct CVisitor; + impl<'de> serde::de::Visitor<'de> for CVisitor { + type Value = CustomMap; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "a map with string keys and values") + } + + fn visit_map(self, mut map: A) -> Result + where + A: serde::de::MapAccess<'de>, + { + let mut inner = HashMap::new(); + while let Some((k, v)) = map.next_entry::()? { + inner.insert(k, v); + } + Ok(CustomMap(inner)) + } + } + // Note: This method will try to deserialize any value. In this test, it will + // invoke the visit_map method in the visitor. + deserializer.deserialize_any(CVisitor) + } + } + + let mut map = HashMap::::new(); + map.insert("key1".into(), "value1".into()); + map.insert("key2".into(), "value2".into()); + + let result: Result = ron::from_str( + r#"( + key1: "value1", + key2: "value2", + )"#, + ); + + assert_eq!(result, Ok(CustomMap(map))); +} diff --git a/tests/non_identifier_identifier.rs b/tests/non_identifier_identifier.rs index 81b6c2cdc..9cb75feb7 100644 --- a/tests/non_identifier_identifier.rs +++ b/tests/non_identifier_identifier.rs @@ -79,7 +79,11 @@ test_non_identifier! { test_u128 => deserialize_u128() } test_non_identifier! { test_f32 => deserialize_f32() } test_non_identifier! { test_f64 => deserialize_f64() } test_non_identifier! { test_char => deserialize_char() } -test_non_identifier! { test_string => deserialize_string() } +// Removed due to fix for #511 - string keys are allowed. +// test_non_identifier! { test_string => deserialize_string() } +// See comment above. If deserialize_str is to be added, it should give the same expected result as +// deserialize_string. deserialize_str and deserialize_string should be consistently implemented. +// test_non_identifier! { test_str => deserialize_str() } test_non_identifier! { test_bytes => deserialize_bytes() } test_non_identifier! { test_byte_buf => deserialize_byte_buf() } test_non_identifier! { test_option => deserialize_option() } From bc45a7dde0d49186b7b224c971814d066de1a2c4 Mon Sep 17 00:00:00 2001 From: Tommy Jensen <1867375+grindvoll@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:36:16 +0200 Subject: [PATCH 2/5] Updated CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f982607f..db5bccff4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix serialising reserved identifiers `true`, `false`, `Some`, `None`, `inf`[`f32`|`f64`], and `Nan`[`f32`|`f64`] ([#487](https://github.com/ron-rs/ron/pull/487)) - Disallow unclosed line comments at the end of `ron::value::RawValue` ([#489](https://github.com/ron-rs/ron/pull/489)) - Fix parsing of struct/variant names starting in `None`, `Some`, `true`, or `false` ([#499](https://github.com/ron-rs/ron/pull/499)) +- Fix deserialising owned string field names in struct formatted maps, allowing deserialization of `serde_json::Value` values ([#511](https://github.com/ron-rs/ron/pull/512)) ### Miscellaneous From 694d74377f4ce2214bbe28b60b158ad4827fcbc0 Mon Sep 17 00:00:00 2001 From: "B. Tommy Jensen" <1867375+grindvoll@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:34:20 +0200 Subject: [PATCH 3/5] Update CHANGELOG.md Co-authored-by: Juniper Tyree <50025784+juntyr@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db5bccff4..dc50458ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,7 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix serialising reserved identifiers `true`, `false`, `Some`, `None`, `inf`[`f32`|`f64`], and `Nan`[`f32`|`f64`] ([#487](https://github.com/ron-rs/ron/pull/487)) - Disallow unclosed line comments at the end of `ron::value::RawValue` ([#489](https://github.com/ron-rs/ron/pull/489)) - Fix parsing of struct/variant names starting in `None`, `Some`, `true`, or `false` ([#499](https://github.com/ron-rs/ron/pull/499)) -- Fix deserialising owned string field names in struct formatted maps, allowing deserialization of `serde_json::Value` values ([#511](https://github.com/ron-rs/ron/pull/512)) +- Fix deserialising owned string field names in structs, allowing deserializing into `serde_json::Value`s ([#511](https://github.com/ron-rs/ron/pull/512)) ### Miscellaneous From 9f191505286009130e314a73f89890205733791e Mon Sep 17 00:00:00 2001 From: Juniper Tyree <50025784+juntyr@users.noreply.github.com> Date: Sat, 7 Oct 2023 00:10:24 +0200 Subject: [PATCH 4/5] Fix code coverage in the test --- tests/511_deserialize_any_map_string_key.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/511_deserialize_any_map_string_key.rs b/tests/511_deserialize_any_map_string_key.rs index 5e12966aa..164daef72 100644 --- a/tests/511_deserialize_any_map_string_key.rs +++ b/tests/511_deserialize_any_map_string_key.rs @@ -15,9 +15,12 @@ fn test_map_custom_deserialize() { struct CVisitor; impl<'de> serde::de::Visitor<'de> for CVisitor { type Value = CustomMap; + + // GRCOV_EXCL_START fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "a map with string keys and values") } + // GRCOV_EXCL_STOP fn visit_map(self, mut map: A) -> Result where From 3dc831f6a1a12350643e8a1fe025022eec0f8a0d Mon Sep 17 00:00:00 2001 From: Juniper Tyree <50025784+juntyr@users.noreply.github.com> Date: Sat, 7 Oct 2023 07:46:25 +0200 Subject: [PATCH 5/5] Fix formatting and add extra test --- tests/511_deserialize_any_map_string_key.rs | 24 ++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/511_deserialize_any_map_string_key.rs b/tests/511_deserialize_any_map_string_key.rs index 164daef72..1ebed521e 100644 --- a/tests/511_deserialize_any_map_string_key.rs +++ b/tests/511_deserialize_any_map_string_key.rs @@ -15,7 +15,7 @@ fn test_map_custom_deserialize() { struct CVisitor; impl<'de> serde::de::Visitor<'de> for CVisitor { type Value = CustomMap; - + // GRCOV_EXCL_START fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { write!(formatter, "a map with string keys and values") @@ -52,3 +52,25 @@ fn test_map_custom_deserialize() { assert_eq!(result, Ok(CustomMap(map))); } + +#[test] +fn test_ron_struct_as_json_map() { + let json: serde_json::Value = ron::from_str("(f1: 0, f2: 1)").unwrap(); + assert_eq!( + json, + serde_json::Value::Object( + [ + ( + String::from("f1"), + serde_json::Value::Number(serde_json::Number::from(0)) + ), + ( + String::from("f2"), + serde_json::Value::Number(serde_json::Number::from(1)) + ), + ] + .into_iter() + .collect() + ) + ); +}