From a0ae9c8ae6803e5760980b24894c6f48b8e11cdd Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Tue, 8 Nov 2022 16:09:42 +0000 Subject: [PATCH 01/19] implement embedded-rust changes --- Cargo.toml | 1 + src/de/mod.rs | 27 +++++++++++++------------- src/lib.rs | 11 +++++++++++ src/ser/map.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++ src/ser/mod.rs | 8 ++++++-- src/ser/struct_.rs | 32 +++++++++++++++---------------- 6 files changed, 96 insertions(+), 31 deletions(-) create mode 100644 src/ser/map.rs diff --git a/Cargo.toml b/Cargo.toml index 5ffafaf8e..1969d3785 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ exclude = [ [dependencies] serde = { version = "^1.0.80", default-features = false, features = ["alloc"] } +serde-cw-value = "0.7.0" [dev-dependencies] serde_derive = "^1.0.80" diff --git a/src/de/mod.rs b/src/de/mod.rs index b66dc58c5..51d65e165 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -579,19 +579,7 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> { /// Unsupported. Can’t make an arbitrary-sized map in no-std. Use a struct with a /// known format, or implement a custom map deserializer / visitor: /// https://serde.rs/deserialize-map.html - fn deserialize_map(self, _visitor: V) -> Result - where - V: Visitor<'de>, - { - unreachable!() - } - - fn deserialize_struct( - self, - _name: &'static str, - _fields: &'static [&'static str], - visitor: V, - ) -> Result + fn deserialize_map(self, visitor: V) -> Result where V: Visitor<'de>, { @@ -608,6 +596,19 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> { } else { Err(Error::InvalidType) } + + } + + fn deserialize_struct( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_map(visitor) } fn deserialize_enum( diff --git a/src/lib.rs b/src/lib.rs index 6a82e060d..2f8bd65f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,6 +65,8 @@ pub use self::ser::{to_string, to_vec}; #[cfg(test)] mod test { + use std::collections::BTreeMap; + use super::*; use serde_derive::{Deserialize, Serialize}; @@ -95,6 +97,7 @@ mod test { published: bool, comments: Vec, stats: Stats, + balances: BTreeMap, } #[test] @@ -107,7 +110,10 @@ mod test { published: false, comments: vec![], stats: Stats { views: 0, score: 0 }, + balances: BTreeMap::new(), }; + let mut balances: BTreeMap = BTreeMap::new(); + balances.insert("chareen".into(), 347); let max = Item { model: Model::Post { category: "fun".to_string(), @@ -122,6 +128,7 @@ mod test { views: std::u64::MAX, score: std::i64::MIN, }, + balances, }; // binary @@ -172,6 +179,9 @@ mod test { author: Address("no-reply@domain.com".to_owned()), }); + let mut balances: BTreeMap = BTreeMap::new(); + balances.insert("chareen".into(), 347); + let item = ModelOrItem::Item(Item { model: Model::Comment, title: "Title".to_owned(), @@ -183,6 +193,7 @@ mod test { views: 110, score: 12, }, + balances }); assert_eq!( diff --git a/src/ser/map.rs b/src/ser/map.rs new file mode 100644 index 000000000..6b35c7017 --- /dev/null +++ b/src/ser/map.rs @@ -0,0 +1,48 @@ +use serde::ser; + +use crate::ser::{Error, Result, Serializer}; + +pub struct SerializeMap<'a> +{ + ser: &'a mut Serializer, + first: bool, +} + +impl<'a> SerializeMap<'a> +{ + pub(crate) fn new(ser: &'a mut Serializer) -> Self { + SerializeMap { ser, first: true } + } +} + +impl<'a> ser::SerializeMap for SerializeMap<'a> +{ + type Ok = (); + type Error = Error; + + fn end(self) -> Result { + self.ser.buf.push(b'}'); + Ok(()) + } + + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ser::Serialize, + { + if !self.first { + self.ser.buf.push(b','); + } + self.first = false; + key.serialize(&mut *self.ser)?; + self.ser.buf.extend_from_slice(b":"); + Ok(()) + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ser::Serialize, + { + value.serialize(&mut *self.ser)?; + Ok(()) + } +} \ No newline at end of file diff --git a/src/ser/mod.rs b/src/ser/mod.rs index b3d8a24d2..bc1beef3d 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -8,9 +8,12 @@ use std::vec::Vec; use self::seq::SerializeSeq; use self::struct_::SerializeStruct; +use self::map::SerializeMap; mod seq; mod struct_; +mod map; + /// Serialization result pub type Result = ::core::result::Result; @@ -153,7 +156,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { type SerializeTuple = SerializeSeq<'a>; type SerializeTupleStruct = Unreachable; type SerializeTupleVariant = SerializeSeq<'a>; - type SerializeMap = Unreachable; + type SerializeMap = SerializeMap<'a>; type SerializeStruct = SerializeStruct<'a>; type SerializeStructVariant = SerializeStruct<'a>; @@ -400,7 +403,8 @@ impl<'a> ser::Serializer for &'a mut Serializer { } fn serialize_map(self, _len: Option) -> Result { - unreachable!() + self.buf.push(b'{'); + Ok(SerializeMap::new(self)) } fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { diff --git a/src/ser/struct_.rs b/src/ser/struct_.rs index 3898db82a..502d03460 100644 --- a/src/ser/struct_.rs +++ b/src/ser/struct_.rs @@ -3,13 +3,13 @@ use serde::ser; use crate::ser::{Error, Result, Serializer}; pub struct SerializeStruct<'a> { - de: &'a mut Serializer, + ser: &'a mut Serializer, first: bool, } impl<'a> SerializeStruct<'a> { - pub(crate) fn new(de: &'a mut Serializer) -> Self { - SerializeStruct { de, first: true } + pub(crate) fn new(ser: &'a mut Serializer) -> Self { + SerializeStruct { ser, first: true } } } @@ -23,21 +23,21 @@ impl<'a> ser::SerializeStruct for SerializeStruct<'a> { { // XXX if `value` is `None` we not produce any output for this field if !self.first { - self.de.buf.push(b','); + self.ser.buf.push(b','); } self.first = false; - self.de.buf.push(b'"'); - self.de.buf.extend_from_slice(key.as_bytes()); - self.de.buf.extend_from_slice(b"\":"); + self.ser.buf.push(b'"'); + self.ser.buf.extend_from_slice(key.as_bytes()); + self.ser.buf.extend_from_slice(b"\":"); - value.serialize(&mut *self.de)?; + value.serialize(&mut *self.ser)?; Ok(()) } fn end(self) -> Result { - self.de.buf.push(b'}'); + self.ser.buf.push(b'}'); Ok(()) } } @@ -52,24 +52,24 @@ impl<'a> ser::SerializeStructVariant for SerializeStruct<'a> { { // XXX if `value` is `None` we not produce any output for this field if !self.first { - self.de.buf.push(b','); + self.ser.buf.push(b','); } self.first = false; - self.de.buf.push(b'"'); - self.de.buf.extend_from_slice(key.as_bytes()); - self.de.buf.extend_from_slice(b"\":"); + self.ser.buf.push(b'"'); + self.ser.buf.extend_from_slice(key.as_bytes()); + self.ser.buf.extend_from_slice(b"\":"); - value.serialize(&mut *self.de)?; + value.serialize(&mut *self.ser)?; Ok(()) } fn end(self) -> Result { // close struct - self.de.buf.push(b'}'); + self.ser.buf.push(b'}'); // close surrounding enum - self.de.buf.push(b'}'); + self.ser.buf.push(b'}'); Ok(()) } } From a0a2658799039906ca7cd5bee3b4347ca1409f7a Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Tue, 8 Nov 2022 16:57:48 +0000 Subject: [PATCH 02/19] remove comment --- src/de/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/de/mod.rs b/src/de/mod.rs index 51d65e165..c4e265144 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -576,9 +576,6 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> { self.deserialize_seq(visitor) } - /// Unsupported. Can’t make an arbitrary-sized map in no-std. Use a struct with a - /// known format, or implement a custom map deserializer / visitor: - /// https://serde.rs/deserialize-map.html fn deserialize_map(self, visitor: V) -> Result where V: Visitor<'de>, From cb45eea25e4e1689038281c9c931331d00b59635 Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Wed, 9 Nov 2022 08:49:55 +0000 Subject: [PATCH 03/19] deserialize with str method for String --- src/de/map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/de/map.rs b/src/de/map.rs index 41f9fe4d7..c15d6595e 100644 --- a/src/de/map.rs +++ b/src/de/map.rs @@ -163,11 +163,11 @@ impl<'de, 'a> de::Deserializer<'de> for MapKey<'a, 'de> { self.de.deserialize_str(visitor) } - fn deserialize_string(self, _visitor: V) -> Result + fn deserialize_string(self, visitor: V) -> Result where V: Visitor<'de>, { - unreachable!() + self.deserialize_str(visitor) } fn deserialize_bytes(self, _visitor: V) -> Result From ebb363bd8851b1f2ad2d33bc126264a7a8e9ee73 Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Wed, 9 Nov 2022 08:51:07 +0000 Subject: [PATCH 04/19] rm serde-cw-value dependency --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1969d3785..5ffafaf8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ exclude = [ [dependencies] serde = { version = "^1.0.80", default-features = false, features = ["alloc"] } -serde-cw-value = "0.7.0" [dev-dependencies] serde_derive = "^1.0.80" From 2112dfcf3bcb24e94e5e97ec117504482fc8fb7d Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Wed, 16 Nov 2022 09:52:05 +0000 Subject: [PATCH 05/19] let map deserializer handle deserialization --- src/de/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/de/map.rs b/src/de/map.rs index c15d6595e..f9dde70e9 100644 --- a/src/de/map.rs +++ b/src/de/map.rs @@ -167,7 +167,7 @@ impl<'de, 'a> de::Deserializer<'de> for MapKey<'a, 'de> { where V: Visitor<'de>, { - self.deserialize_str(visitor) + self.de.deserialize_string(visitor) } fn deserialize_bytes(self, _visitor: V) -> Result From 62b6f2636ac9b8eaee7a1c4a8e8c79762e4e6be8 Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Wed, 16 Nov 2022 10:15:36 +0000 Subject: [PATCH 06/19] add serialization test for map structure --- src/ser/mod.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index bc1beef3d..9cde7aaa5 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -534,6 +534,7 @@ impl ser::SerializeStructVariant for Unreachable { #[cfg(test)] mod tests { + use super::to_string; use serde_derive::Serialize; @@ -983,6 +984,30 @@ mod tests { ); } + #[test] + fn btree_map() { + use std::collections::BTreeMap; + // empty map + assert_eq!(to_string(&BTreeMap::<(),()>::new()).unwrap(), r#"{}"#); + + let mut two_values = BTreeMap::new(); + two_values.insert("my_name", "joseph"); + two_values.insert("her_name", "aline"); + assert_eq!( + to_string(&two_values).unwrap(), + r#"{"her_name":"aline","my_name":"joseph"}"# + ); + + let mut nested_map = BTreeMap::new(); + nested_map.insert("two_entries", two_values.clone()); + + two_values.remove("my_name"); + nested_map.insert("one_entry", two_values); + assert_eq!( + to_string(&nested_map).unwrap(), + r#"{"one_entry":{"her_name":"aline"},"two_entries":{"her_name":"aline","my_name":"joseph"}}"# + ); + } use serde_derive::Deserialize; #[test] From ca4e8ec2adec22e895703262b52b668eb72dd074 Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Wed, 16 Nov 2022 10:16:15 +0000 Subject: [PATCH 07/19] format --- src/de/mod.rs | 1 - src/lib.rs | 10 +++++----- src/ser/map.rs | 11 ++++------- src/ser/mod.rs | 7 +++---- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/de/mod.rs b/src/de/mod.rs index c4e265144..5315fc587 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -593,7 +593,6 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> { } else { Err(Error::InvalidType) } - } fn deserialize_struct( diff --git a/src/lib.rs b/src/lib.rs index 2f8bd65f4..4ce4e51e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -97,7 +97,7 @@ mod test { published: bool, comments: Vec, stats: Stats, - balances: BTreeMap, + balances: BTreeMap, } #[test] @@ -110,9 +110,9 @@ mod test { published: false, comments: vec![], stats: Stats { views: 0, score: 0 }, - balances: BTreeMap::new(), + balances: BTreeMap::new(), }; - let mut balances: BTreeMap = BTreeMap::new(); + let mut balances: BTreeMap = BTreeMap::new(); balances.insert("chareen".into(), 347); let max = Item { model: Model::Post { @@ -179,7 +179,7 @@ mod test { author: Address("no-reply@domain.com".to_owned()), }); - let mut balances: BTreeMap = BTreeMap::new(); + let mut balances: BTreeMap = BTreeMap::new(); balances.insert("chareen".into(), 347); let item = ModelOrItem::Item(Item { @@ -193,7 +193,7 @@ mod test { views: 110, score: 12, }, - balances + balances, }); assert_eq!( diff --git a/src/ser/map.rs b/src/ser/map.rs index 6b35c7017..51415f8e6 100644 --- a/src/ser/map.rs +++ b/src/ser/map.rs @@ -2,21 +2,18 @@ use serde::ser; use crate::ser::{Error, Result, Serializer}; -pub struct SerializeMap<'a> -{ +pub struct SerializeMap<'a> { ser: &'a mut Serializer, first: bool, } -impl<'a> SerializeMap<'a> -{ +impl<'a> SerializeMap<'a> { pub(crate) fn new(ser: &'a mut Serializer) -> Self { SerializeMap { ser, first: true } } } -impl<'a> ser::SerializeMap for SerializeMap<'a> -{ +impl<'a> ser::SerializeMap for SerializeMap<'a> { type Ok = (); type Error = Error; @@ -45,4 +42,4 @@ impl<'a> ser::SerializeMap for SerializeMap<'a> value.serialize(&mut *self.ser)?; Ok(()) } -} \ No newline at end of file +} diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 9cde7aaa5..f3cb8c433 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -6,14 +6,13 @@ use serde::ser; use std::vec::Vec; +use self::map::SerializeMap; use self::seq::SerializeSeq; use self::struct_::SerializeStruct; -use self::map::SerializeMap; +mod map; mod seq; mod struct_; -mod map; - /// Serialization result pub type Result = ::core::result::Result; @@ -988,7 +987,7 @@ mod tests { fn btree_map() { use std::collections::BTreeMap; // empty map - assert_eq!(to_string(&BTreeMap::<(),()>::new()).unwrap(), r#"{}"#); + assert_eq!(to_string(&BTreeMap::<(), ()>::new()).unwrap(), r#"{}"#); let mut two_values = BTreeMap::new(); two_values.insert("my_name", "joseph"); From 2e6554a0f498d5ecf19e543d3382d01bccf568a2 Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Wed, 16 Nov 2022 11:11:19 +0000 Subject: [PATCH 08/19] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fda356773..f43e7dd71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +### Unreleased +- Add support for map (de)serialization. + ## [0.4.1] - 2022-05-05 ### Changed From 39a4cb8cc68e4975fd7049f7fdec441f424f3555 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 16 Nov 2022 21:09:45 +0100 Subject: [PATCH 09/19] Move Deserialize import into test --- src/ser/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index f3cb8c433..2183d49f4 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -1007,10 +1007,11 @@ mod tests { r#"{"one_entry":{"her_name":"aline"},"two_entries":{"her_name":"aline","my_name":"joseph"}}"# ); } - use serde_derive::Deserialize; #[test] fn serialize_embedded_enum() { + use serde_derive::Deserialize; + #[derive(Debug, Deserialize, Serialize, PartialEq)] #[serde(rename_all = "lowercase")] pub enum MyResult { From b677f792f1956b0cc13dff9ab14344f72fdb5120 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 16 Nov 2022 21:10:08 +0100 Subject: [PATCH 10/19] Add HashMap test --- src/ser/mod.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 2183d49f4..bc46c215d 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -1008,6 +1008,30 @@ mod tests { ); } + #[test] + fn hash_map() { + use std::collections::HashMap; + + // empty map + assert_eq!(to_string(&HashMap::<(), ()>::new()).unwrap(), r#"{}"#); + + // One element + let mut map = HashMap::new(); + map.insert("my_age", 28); + assert_eq!(to_string(&map).unwrap(), r#"{"my_age":28}"#); + + // HashMap does not have deterministic iteration order (except in the Wasm target). + // So the two element map is serialized as one of two options. + let mut two_values = HashMap::new(); + two_values.insert("my_name", "joseph"); + two_values.insert("her_name", "aline"); + let serialized = to_string(&two_values).unwrap(); + assert!( + serialized == r#"{"her_name":"aline","my_name":"joseph"}"# + || serialized == r#"{"my_name":"joseph","her_name":"aline"}"# + ); + } + #[test] fn serialize_embedded_enum() { use serde_derive::Deserialize; From cdc78130b25d65981b74a5e4a10a9f8667292d36 Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Mon, 21 Nov 2022 14:50:44 +0000 Subject: [PATCH 11/19] Implement MapKeySerializer --- src/ser/map.rs | 5 +- src/ser/mod.rs | 328 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 331 insertions(+), 2 deletions(-) diff --git a/src/ser/map.rs b/src/ser/map.rs index 51415f8e6..c8b980541 100644 --- a/src/ser/map.rs +++ b/src/ser/map.rs @@ -2,6 +2,8 @@ use serde::ser; use crate::ser::{Error, Result, Serializer}; +use super::MapKeySerializer; + pub struct SerializeMap<'a> { ser: &'a mut Serializer, first: bool, @@ -30,7 +32,8 @@ impl<'a> ser::SerializeMap for SerializeMap<'a> { self.ser.buf.push(b','); } self.first = false; - key.serialize(&mut *self.ser)?; + // Use key serializer to unsure key type validity. + key.serialize(MapKeySerializer { ser: self.ser })?; self.ser.buf.extend_from_slice(b":"); Ok(()) } diff --git a/src/ser/mod.rs b/src/ser/mod.rs index bc46c215d..52f120420 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -2,7 +2,7 @@ use std::{error, fmt}; -use serde::ser; +use serde::{ser, Serialize}; use std::vec::Vec; @@ -531,6 +531,192 @@ impl ser::SerializeStructVariant for Unreachable { } } +/// Wrapper around Serializer that only allows serialization of valid JSON key types (strings). +struct MapKeySerializer<'a> { + ser: &'a mut Serializer, +} + +fn key_must_be_a_string() -> Error { + Error::Custom("JSON object key is required to be a string type.".to_string()) +} + +impl<'a> ser::Serializer for MapKeySerializer<'a> { + type Ok = (); + type Error = Error; + type SerializeSeq = SerializeSeq<'a>; + type SerializeTuple = SerializeSeq<'a>; + type SerializeTupleStruct = Unreachable; + type SerializeTupleVariant = SerializeSeq<'a>; + type SerializeMap = SerializeMap<'a>; + type SerializeStruct = SerializeStruct<'a>; + type SerializeStructVariant = SerializeStruct<'a>; + + fn serialize_bool(self, _value: bool) -> Result<()> { + Err(key_must_be_a_string()) + } + #[inline] + fn serialize_str(self, value: &str) -> Result<()> { + self.ser.serialize_str(value) + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<()> { + self.ser.serialize_str(variant) + } + + #[inline] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_i8(self, _value: i8) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_i16(self, _value: i16) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_i32(self, _value: i32) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_i64(self, _value: i64) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_i128(self, _value: i128) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_u8(self, _value: u8) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_u16(self, _value: u16) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_u32(self, _value: u32) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_u64(self, _value: u64) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_u128(self, _value: u128) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_f32(self, _value: f32) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_f64(self, _value: f64) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_char(self, value: char) -> Result<()> { + self.ser.serialize_str(&value.to_string()) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_unit(self) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_none(self) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_some(self, _value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn collect_str(self, _value: &T) -> Result<()> + where + T: ?Sized + fmt::Display, + { + unreachable!() + } +} + #[cfg(test)] mod tests { @@ -1020,6 +1206,25 @@ mod tests { map.insert("my_age", 28); assert_eq!(to_string(&map).unwrap(), r#"{"my_age":28}"#); + #[derive(Debug, Serialize, PartialEq, Eq, Hash)] + pub struct NewType(String); + + // New type wrappers around String types work as keys + let mut map = HashMap::new(); + map.insert(NewType(String::from("my_age")), 44); + assert_eq!(to_string(&map).unwrap(), r#"{"my_age":44}"#); + + #[derive(Debug, Serialize, PartialEq, Eq, Hash)] + #[serde(rename_all = "lowercase")] + pub enum MyResult { + Err, + } + + // Unit variants are also valid keys + let mut map = HashMap::new(); + map.insert(MyResult::Err, 404); + assert_eq!(to_string(&map).unwrap(), r#"{"err":404}"#); + // HashMap does not have deterministic iteration order (except in the Wasm target). // So the two element map is serialized as one of two options. let mut two_values = HashMap::new(); @@ -1032,6 +1237,127 @@ mod tests { ); } + #[test] + fn invalid_json_key() { + use crate::ser::key_must_be_a_string; + use std::collections::HashMap; + + // i8 key + let mut map = HashMap::new(); + map.insert(1i8, "my_age"); + assert_eq!( + to_string(&map).unwrap_err().to_string(), + key_must_be_a_string().to_string() + ); + + // i16 key + let mut map = HashMap::new(); + map.insert(40i16, "my_age"); + assert_eq!( + to_string(&map).unwrap_err().to_string(), + key_must_be_a_string().to_string() + ); + + // i32 key + let mut map = HashMap::new(); + map.insert(40i32, "my_age"); + assert_eq!( + to_string(&map).unwrap_err().to_string(), + key_must_be_a_string().to_string() + ); + + // i64 key + let mut map = HashMap::new(); + map.insert(40i64, "my_age"); + assert_eq!( + to_string(&map).unwrap_err().to_string(), + key_must_be_a_string().to_string() + ); + + // u8 key + let mut map = HashMap::new(); + map.insert(1u8, "my_age"); + assert_eq!( + to_string(&map).unwrap_err().to_string(), + key_must_be_a_string().to_string() + ); + + // u16 key + let mut map = HashMap::new(); + map.insert(40u16, "my_age"); + assert_eq!( + to_string(&map).unwrap_err().to_string(), + key_must_be_a_string().to_string() + ); + + // u32 key + let mut map = HashMap::new(); + map.insert(40u32, "my_age"); + assert_eq!( + to_string(&map).unwrap_err().to_string(), + key_must_be_a_string().to_string() + ); + + // u64 key + let mut map = HashMap::new(); + map.insert(40u64, "my_age"); + assert_eq!( + to_string(&map).unwrap_err().to_string(), + key_must_be_a_string().to_string() + ); + + #[derive(Debug, Serialize, PartialEq, Eq, Hash)] + #[serde(rename_all = "lowercase")] + pub enum MyResult { + Unit(()), + Ok(Response), + } + #[derive(Debug, Serialize, PartialEq, Eq, Hash)] + pub struct Response { + pub log: Option, + pub count: i64, + pub list: Vec, + } + + // unit enum + let mut map = HashMap::new(); + map.insert(MyResult::Unit(()), "my_age"); + assert_eq!( + to_string(&map).unwrap_err().to_string(), + key_must_be_a_string().to_string() + ); + + // struct enum + let mut map = HashMap::new(); + map.insert( + MyResult::Ok(Response { + log: None, + count: 1, + list: vec![6], + }), + "my_age", + ); + assert_eq!( + to_string(&map).unwrap_err().to_string(), + key_must_be_a_string().to_string() + ); + + // Struct + let mut map = HashMap::new(); + map.insert( + Response { + log: None, + count: 1, + list: vec![6], + }, + "my_age", + ); + assert_eq!( + to_string(&map).unwrap_err().to_string(), + key_must_be_a_string().to_string() + ); + } + #[test] fn serialize_embedded_enum() { use serde_derive::Deserialize; From d1f21abfbdc0f1f4c373395d95a9f24fc4e97b60 Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Tue, 22 Nov 2022 11:10:52 +0000 Subject: [PATCH 12/19] implement number key serialization as string --- src/ser/mod.rs | 137 +++++++++++++++++++++++++++---------------------- 1 file changed, 75 insertions(+), 62 deletions(-) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 52f120420..dbd351479 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -540,6 +540,28 @@ fn key_must_be_a_string() -> Error { Error::Custom("JSON object key is required to be a string type.".to_string()) } +macro_rules! serialize_unsigned_key { + ($self:ident, $N:expr, $v:expr) => {{ + let ser = $self.ser; + ser.buf.push(b'"'); + let res: Result = serialize_unsigned!(ser, $N, $v); + res?; + ser.buf.push(b'"'); + Ok(()) + }}; +} + +macro_rules! serialize_signed_key { + ($self:ident, $N:expr, $v:expr, $ixx:ident, $uxx:ident) => {{ + let ser = $self.ser; + ser.buf.push(b'"'); + let res: Result = serialize_signed!(ser, $N, $v, $ixx, $uxx); + res?; + ser.buf.push(b'"'); + Ok(()) + }}; +} + impl<'a> ser::Serializer for MapKeySerializer<'a> { type Ok = (); type Error = Error; @@ -577,44 +599,44 @@ impl<'a> ser::Serializer for MapKeySerializer<'a> { value.serialize(self) } - fn serialize_i8(self, _value: i8) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_i8(self, value: i8) -> Result<()> { + serialize_signed_key!(self, 4, value, i8, u8) } - fn serialize_i16(self, _value: i16) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_i16(self, value: i16) -> Result<()> { + serialize_signed_key!(self, 6, value, i16, u16) } - fn serialize_i32(self, _value: i32) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_i32(self, value: i32) -> Result<()> { + serialize_signed_key!(self, 11, value, i32, u32) } - fn serialize_i64(self, _value: i64) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_i64(self, value: i64) -> Result<()> { + serialize_signed_key!(self, 20, value, i64, u64) } - fn serialize_i128(self, _value: i128) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_i128(self, value: i128) -> Result<()> { + serialize_signed_key!(self, 40, value, i128, u128) } - fn serialize_u8(self, _value: u8) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_u8(self, value: u8) -> Result<()> { + serialize_unsigned_key!(self, 3, value) } - fn serialize_u16(self, _value: u16) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_u16(self, value: u16) -> Result<()> { + serialize_unsigned_key!(self, 5, value) } - fn serialize_u32(self, _value: u32) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_u32(self, value: u32) -> Result<()> { + serialize_unsigned_key!(self, 10, value) } - fn serialize_u64(self, _value: u64) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_u64(self, value: u64) -> Result<()> { + serialize_unsigned_key!(self, 20, value) } - fn serialize_u128(self, _value: u128) -> Result<()> { - Err(key_must_be_a_string()) + fn serialize_u128(self, value: u128) -> Result<()> { + serialize_unsigned_key!(self, 39, value) } fn serialize_f32(self, _value: f32) -> Result<()> { @@ -1238,73 +1260,64 @@ mod tests { } #[test] - fn invalid_json_key() { - use crate::ser::key_must_be_a_string; + fn number_key() { use std::collections::HashMap; // i8 key let mut map = HashMap::new(); - map.insert(1i8, "my_age"); - assert_eq!( - to_string(&map).unwrap_err().to_string(), - key_must_be_a_string().to_string() - ); + map.insert(10i8, "my_age"); + assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); // i16 key let mut map = HashMap::new(); - map.insert(40i16, "my_age"); - assert_eq!( - to_string(&map).unwrap_err().to_string(), - key_must_be_a_string().to_string() - ); + map.insert(10i16, "my_age"); + assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); // i32 key let mut map = HashMap::new(); - map.insert(40i32, "my_age"); - assert_eq!( - to_string(&map).unwrap_err().to_string(), - key_must_be_a_string().to_string() - ); + map.insert(10i32, "my_age"); + assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); // i64 key let mut map = HashMap::new(); - map.insert(40i64, "my_age"); - assert_eq!( - to_string(&map).unwrap_err().to_string(), - key_must_be_a_string().to_string() - ); + map.insert(10i64, "my_age"); + assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); + + // i128 key + let mut map = HashMap::new(); + map.insert(10i128, "my_age"); + assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); // u8 key let mut map = HashMap::new(); - map.insert(1u8, "my_age"); - assert_eq!( - to_string(&map).unwrap_err().to_string(), - key_must_be_a_string().to_string() - ); + map.insert(10u8, "my_age"); + assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); // u16 key let mut map = HashMap::new(); - map.insert(40u16, "my_age"); - assert_eq!( - to_string(&map).unwrap_err().to_string(), - key_must_be_a_string().to_string() - ); + map.insert(10u16, "my_age"); + assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); // u32 key let mut map = HashMap::new(); - map.insert(40u32, "my_age"); - assert_eq!( - to_string(&map).unwrap_err().to_string(), - key_must_be_a_string().to_string() - ); + map.insert(10u32, "my_age"); + assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); // u64 key let mut map = HashMap::new(); - map.insert(40u64, "my_age"); - assert_eq!( - to_string(&map).unwrap_err().to_string(), - key_must_be_a_string().to_string() - ); + map.insert(10u64, "my_age"); + assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); + + // u128 key + let mut map = HashMap::new(); + map.insert(10u128, "my_age"); + assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); + } + + #[test] + fn invalid_json_key() { + use crate::ser::key_must_be_a_string; + use std::collections::HashMap; #[derive(Debug, Serialize, PartialEq, Eq, Hash)] #[serde(rename_all = "lowercase")] From 784121c2f48f033d8452cb6600c5c416421e72df Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Tue, 22 Nov 2022 11:31:21 +0000 Subject: [PATCH 13/19] add failing number key deserialization test --- src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 4ce4e51e3..f2f5c244e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -214,4 +214,16 @@ mod test { item ); } + + // #[test] + // fn numbered_keys() { + // let mut ranking: BTreeMap = BTreeMap::new(); + // ranking.insert(1, "Elon".to_string()); + // ranking.insert(2, "Bazos".to_string()); + + // assert_eq!( + // from_str::>(&to_string(&ranking).unwrap()).unwrap(), + // ranking + // ); + // } } From c1b254c97495f47a9791df2546a9551cdfa85b22 Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Tue, 22 Nov 2022 11:39:42 +0000 Subject: [PATCH 14/19] move MapKeySerializer implementation --- src/ser/map.rs | 214 +++++++++++++++++++++++++++++++++++++++++++++++- src/ser/mod.rs | 216 ++----------------------------------------------- 2 files changed, 218 insertions(+), 212 deletions(-) diff --git a/src/ser/map.rs b/src/ser/map.rs index c8b980541..c82c2ee34 100644 --- a/src/ser/map.rs +++ b/src/ser/map.rs @@ -1,8 +1,10 @@ -use serde::ser; +use std::fmt; + +use serde::{ser, Serialize}; use crate::ser::{Error, Result, Serializer}; -use super::MapKeySerializer; +use super::{seq::SerializeSeq, struct_::SerializeStruct, Unreachable}; pub struct SerializeMap<'a> { ser: &'a mut Serializer, @@ -46,3 +48,211 @@ impl<'a> ser::SerializeMap for SerializeMap<'a> { Ok(()) } } + +/// Wrapper around Serializer that only allows serialization of valid JSON key types (strings). +struct MapKeySerializer<'a> { + ser: &'a mut Serializer, +} + +pub(crate) fn key_must_be_a_string() -> Error { + Error::Custom("JSON object key is required to be a string type.".to_string()) +} + +macro_rules! serialize_unsigned_key { + ($self:ident, $N:expr, $v:expr) => {{ + let ser = $self.ser; + ser.buf.push(b'"'); + let res: Result = super::serialize_unsigned!(ser, $N, $v); + res?; + ser.buf.push(b'"'); + Ok(()) + }}; +} + +macro_rules! serialize_signed_key { + ($self:ident, $N:expr, $v:expr, $ixx:ident, $uxx:ident) => {{ + let ser = $self.ser; + ser.buf.push(b'"'); + let res: Result = super::serialize_signed!(ser, $N, $v, $ixx, $uxx); + res?; + ser.buf.push(b'"'); + Ok(()) + }}; +} + +impl<'a> ser::Serializer for MapKeySerializer<'a> { + type Ok = (); + type Error = Error; + type SerializeSeq = SerializeSeq<'a>; + type SerializeTuple = SerializeSeq<'a>; + type SerializeTupleStruct = Unreachable; + type SerializeTupleVariant = SerializeSeq<'a>; + type SerializeMap = SerializeMap<'a>; + type SerializeStruct = SerializeStruct<'a>; + type SerializeStructVariant = SerializeStruct<'a>; + + fn serialize_bool(self, _value: bool) -> Result<()> { + Err(key_must_be_a_string()) + } + #[inline] + fn serialize_str(self, value: &str) -> Result<()> { + self.ser.serialize_str(value) + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<()> { + self.ser.serialize_str(variant) + } + + #[inline] + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_i8(self, value: i8) -> Result<()> { + serialize_signed_key!(self, 4, value, i8, u8) + } + + fn serialize_i16(self, value: i16) -> Result<()> { + serialize_signed_key!(self, 6, value, i16, u16) + } + + fn serialize_i32(self, value: i32) -> Result<()> { + serialize_signed_key!(self, 11, value, i32, u32) + } + + fn serialize_i64(self, value: i64) -> Result<()> { + serialize_signed_key!(self, 20, value, i64, u64) + } + + fn serialize_i128(self, value: i128) -> Result<()> { + serialize_signed_key!(self, 40, value, i128, u128) + } + + fn serialize_u8(self, value: u8) -> Result<()> { + serialize_unsigned_key!(self, 3, value) + } + + fn serialize_u16(self, value: u16) -> Result<()> { + serialize_unsigned_key!(self, 5, value) + } + + fn serialize_u32(self, value: u32) -> Result<()> { + serialize_unsigned_key!(self, 10, value) + } + + fn serialize_u64(self, value: u64) -> Result<()> { + serialize_unsigned_key!(self, 20, value) + } + + fn serialize_u128(self, value: u128) -> Result<()> { + serialize_unsigned_key!(self, 39, value) + } + + fn serialize_f32(self, _value: f32) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_f64(self, _value: f64) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_char(self, value: char) -> Result<()> { + self.ser.serialize_str(&value.to_string()) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_unit(self) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_none(self) -> Result<()> { + Err(key_must_be_a_string()) + } + + fn serialize_some(self, _value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(key_must_be_a_string()) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Err(key_must_be_a_string()) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(key_must_be_a_string()) + } + + fn collect_str(self, _value: &T) -> Result<()> + where + T: ?Sized + fmt::Display, + { + unreachable!() + } +} diff --git a/src/ser/mod.rs b/src/ser/mod.rs index dbd351479..8490157b8 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -2,7 +2,7 @@ use std::{error, fmt}; -use serde::{ser, Serialize}; +use serde::ser; use std::vec::Vec; @@ -99,6 +99,8 @@ macro_rules! serialize_unsigned { Ok(()) }}; } +// Export for use in map +pub(crate) use serialize_unsigned; macro_rules! serialize_signed { ($self:ident, $N:expr, $v:expr, $ixx:ident, $uxx:ident) => {{ @@ -133,6 +135,8 @@ macro_rules! serialize_signed { Ok(()) }}; } +// Export for use in map +pub(crate) use serialize_signed; /// Upper-case hex for value in 0..16, encoded as ASCII bytes fn hex_4bit(c: u8) -> u8 { @@ -531,214 +535,6 @@ impl ser::SerializeStructVariant for Unreachable { } } -/// Wrapper around Serializer that only allows serialization of valid JSON key types (strings). -struct MapKeySerializer<'a> { - ser: &'a mut Serializer, -} - -fn key_must_be_a_string() -> Error { - Error::Custom("JSON object key is required to be a string type.".to_string()) -} - -macro_rules! serialize_unsigned_key { - ($self:ident, $N:expr, $v:expr) => {{ - let ser = $self.ser; - ser.buf.push(b'"'); - let res: Result = serialize_unsigned!(ser, $N, $v); - res?; - ser.buf.push(b'"'); - Ok(()) - }}; -} - -macro_rules! serialize_signed_key { - ($self:ident, $N:expr, $v:expr, $ixx:ident, $uxx:ident) => {{ - let ser = $self.ser; - ser.buf.push(b'"'); - let res: Result = serialize_signed!(ser, $N, $v, $ixx, $uxx); - res?; - ser.buf.push(b'"'); - Ok(()) - }}; -} - -impl<'a> ser::Serializer for MapKeySerializer<'a> { - type Ok = (); - type Error = Error; - type SerializeSeq = SerializeSeq<'a>; - type SerializeTuple = SerializeSeq<'a>; - type SerializeTupleStruct = Unreachable; - type SerializeTupleVariant = SerializeSeq<'a>; - type SerializeMap = SerializeMap<'a>; - type SerializeStruct = SerializeStruct<'a>; - type SerializeStructVariant = SerializeStruct<'a>; - - fn serialize_bool(self, _value: bool) -> Result<()> { - Err(key_must_be_a_string()) - } - #[inline] - fn serialize_str(self, value: &str) -> Result<()> { - self.ser.serialize_str(value) - } - - #[inline] - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result<()> { - self.ser.serialize_str(variant) - } - - #[inline] - fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - value.serialize(self) - } - - fn serialize_i8(self, value: i8) -> Result<()> { - serialize_signed_key!(self, 4, value, i8, u8) - } - - fn serialize_i16(self, value: i16) -> Result<()> { - serialize_signed_key!(self, 6, value, i16, u16) - } - - fn serialize_i32(self, value: i32) -> Result<()> { - serialize_signed_key!(self, 11, value, i32, u32) - } - - fn serialize_i64(self, value: i64) -> Result<()> { - serialize_signed_key!(self, 20, value, i64, u64) - } - - fn serialize_i128(self, value: i128) -> Result<()> { - serialize_signed_key!(self, 40, value, i128, u128) - } - - fn serialize_u8(self, value: u8) -> Result<()> { - serialize_unsigned_key!(self, 3, value) - } - - fn serialize_u16(self, value: u16) -> Result<()> { - serialize_unsigned_key!(self, 5, value) - } - - fn serialize_u32(self, value: u32) -> Result<()> { - serialize_unsigned_key!(self, 10, value) - } - - fn serialize_u64(self, value: u64) -> Result<()> { - serialize_unsigned_key!(self, 20, value) - } - - fn serialize_u128(self, value: u128) -> Result<()> { - serialize_unsigned_key!(self, 39, value) - } - - fn serialize_f32(self, _value: f32) -> Result<()> { - Err(key_must_be_a_string()) - } - - fn serialize_f64(self, _value: f64) -> Result<()> { - Err(key_must_be_a_string()) - } - - fn serialize_char(self, value: char) -> Result<()> { - self.ser.serialize_str(&value.to_string()) - } - - fn serialize_bytes(self, _value: &[u8]) -> Result<()> { - Err(key_must_be_a_string()) - } - - fn serialize_unit(self) -> Result<()> { - Err(key_must_be_a_string()) - } - - fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { - Err(key_must_be_a_string()) - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _value: &T, - ) -> Result<()> - where - T: ?Sized + Serialize, - { - Err(key_must_be_a_string()) - } - - fn serialize_none(self) -> Result<()> { - Err(key_must_be_a_string()) - } - - fn serialize_some(self, _value: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - Err(key_must_be_a_string()) - } - - fn serialize_seq(self, _len: Option) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_tuple(self, _len: usize) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - _len: usize, - ) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_map(self, _len: Option) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { - Err(key_must_be_a_string()) - } - - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - Err(key_must_be_a_string()) - } - - fn collect_str(self, _value: &T) -> Result<()> - where - T: ?Sized + fmt::Display, - { - unreachable!() - } -} - #[cfg(test)] mod tests { @@ -1316,7 +1112,7 @@ mod tests { #[test] fn invalid_json_key() { - use crate::ser::key_must_be_a_string; + use crate::ser::map::key_must_be_a_string; use std::collections::HashMap; #[derive(Debug, Serialize, PartialEq, Eq, Hash)] From 227daee0037643614ef8290dbbd73e0603aed497 Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Tue, 22 Nov 2022 12:45:20 +0000 Subject: [PATCH 15/19] Implement deserialize for number map keys --- src/de/map.rs | 100 +++++++++++++++++++++++++++++++++++++++++--------- src/de/mod.rs | 15 ++++++++ src/lib.rs | 12 ------ 3 files changed, 97 insertions(+), 30 deletions(-) diff --git a/src/de/map.rs b/src/de/map.rs index f9dde70e9..17b88800f 100644 --- a/src/de/map.rs +++ b/src/de/map.rs @@ -1,6 +1,5 @@ -use serde::de::{self, Visitor}; - use crate::de::{Deserializer, Error}; +use serde::de::{self, Visitor}; pub struct MapAccess<'a, 'b> { de: &'a mut Deserializer<'b>, @@ -13,6 +12,56 @@ impl<'a, 'b> MapAccess<'a, 'b> { } } +macro_rules! deserialize_signed_key { + ($self:ident, $visitor:ident, $ixx:ident, $visit_ixx:ident) => {{ + let de = $self.de; + match de.parse_whitespace().ok_or(Error::EofWhileParsingValue)? { + b'"' => de.eat_char(), + _ => return Err(Error::InvalidType), + }; + + let result = match de.peek() { + // after rust merged or-patterns feature, these two clause can be merged. + // error[E0658]: or-patterns syntax is experimental + Some(b'0'..=b'9') => super::deserialize_signed!(de, $visitor, $ixx, $visit_ixx), + Some(b'-') => super::deserialize_signed!(de, $visitor, $ixx, $visit_ixx), + _ => return Err(Error::InvalidType), + }; + match de.peek() { + Some(b'"') => { + de.eat_char(); + result + } + _ => Err(Error::InvalidType), + } + }}; +} + +macro_rules! deserialize_unsigned_key { + ($self:ident, $visitor:ident, $ixx:ident, $visit_ixx:ident) => {{ + let de = $self.de; + match de.parse_whitespace().ok_or(Error::EofWhileParsingValue)? { + b'"' => de.eat_char(), + _ => return Err(Error::InvalidType), + }; + + let result = match de.peek() { + // after rust merged or-patterns feature, these two clause can be merged. + // error[E0658]: or-patterns syntax is experimental + Some(b'0'..=b'9') => super::deserialize_unsigned!(de, $visitor, $ixx, $visit_ixx), + Some(b'-') => super::deserialize_unsigned!(de, $visitor, $ixx, $visit_ixx), + _ => return Err(Error::InvalidType), + }; + match de.peek() { + Some(b'"') => { + de.eat_char(); + result + } + _ => Err(Error::InvalidType), + } + }}; +} + impl<'a, 'de> de::MapAccess<'de> for MapAccess<'a, 'de> { type Error = Error; @@ -79,60 +128,75 @@ impl<'de, 'a> de::Deserializer<'de> for MapKey<'a, 'de> { unreachable!() } - fn deserialize_i8(self, _visitor: V) -> Result + fn deserialize_i8(self, visitor: V) -> Result where V: Visitor<'de>, { - unreachable!() + deserialize_signed_key!(self, visitor, i8, visit_i8) } - fn deserialize_i16(self, _visitor: V) -> Result + fn deserialize_i16(self, visitor: V) -> Result where V: Visitor<'de>, { - unreachable!() + deserialize_signed_key!(self, visitor, i16, visit_i16) } - fn deserialize_i32(self, _visitor: V) -> Result + fn deserialize_i32(self, visitor: V) -> Result where V: Visitor<'de>, { - unreachable!() + deserialize_signed_key!(self, visitor, i32, visit_i32) } - fn deserialize_i64(self, _visitor: V) -> Result + fn deserialize_i64(self, visitor: V) -> Result where V: Visitor<'de>, { - unreachable!() + deserialize_signed_key!(self, visitor, i64, visit_i64) } - fn deserialize_u8(self, _visitor: V) -> Result + fn deserialize_i128(self, visitor: V) -> Result where V: Visitor<'de>, { - unreachable!() + // default implementation includes string unparsing + self.de.deserialize_i128(visitor) } - fn deserialize_u16(self, _visitor: V) -> Result + fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de>, { - unreachable!() + deserialize_unsigned_key!(self, visitor, u8, visit_u8) } - fn deserialize_u32(self, _visitor: V) -> Result + fn deserialize_u16(self, visitor: V) -> Result where V: Visitor<'de>, { - unreachable!() + deserialize_unsigned_key!(self, visitor, u16, visit_u16) } - fn deserialize_u64(self, _visitor: V) -> Result + fn deserialize_u32(self, visitor: V) -> Result where V: Visitor<'de>, { - unreachable!() + deserialize_unsigned_key!(self, visitor, u32, visit_u32) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + deserialize_unsigned_key!(self, visitor, u64, visit_u64) + } + + fn deserialize_u128(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.de.deserialize_u128(visitor) } fn deserialize_f32(self, _visitor: V) -> Result diff --git a/src/de/mod.rs b/src/de/mod.rs index 5315fc587..c17c7c4ba 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -203,6 +203,7 @@ macro_rules! deserialize_unsigned { } }}; } +pub(crate) use deserialize_unsigned; macro_rules! deserialize_signed { ($self:ident, $visitor:ident, $ixx:ident, $visit_ixx:ident) => {{ @@ -245,6 +246,7 @@ macro_rules! deserialize_signed { } }}; } +pub(crate) use deserialize_signed; impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> { type Error = Error; @@ -1094,6 +1096,19 @@ mod tests { ); } + #[test] + fn numbered_key_maps() { + use std::collections::BTreeMap; + let mut ranking: BTreeMap = BTreeMap::new(); + ranking.insert(1, "Elon".to_string()); + ranking.insert(2, "Bazos".to_string()); + + assert_eq!( + from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), + ranking + ); + } + #[test] fn deserialize_optional_vector() { #[derive(Debug, Deserialize, PartialEq)] diff --git a/src/lib.rs b/src/lib.rs index f2f5c244e..4ce4e51e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -214,16 +214,4 @@ mod test { item ); } - - // #[test] - // fn numbered_keys() { - // let mut ranking: BTreeMap = BTreeMap::new(); - // ranking.insert(1, "Elon".to_string()); - // ranking.insert(2, "Bazos".to_string()); - - // assert_eq!( - // from_str::>(&to_string(&ranking).unwrap()).unwrap(), - // ranking - // ); - // } } From 96d4319519e5576cf967657ff7affcaa7496b810 Mon Sep 17 00:00:00 2001 From: CyberHoward Date: Tue, 22 Nov 2022 12:46:46 +0000 Subject: [PATCH 16/19] format --- src/de/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/de/mod.rs b/src/de/mod.rs index c17c7c4ba..61e740b78 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1102,7 +1102,7 @@ mod tests { let mut ranking: BTreeMap = BTreeMap::new(); ranking.insert(1, "Elon".to_string()); ranking.insert(2, "Bazos".to_string()); - + assert_eq!( from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), ranking From ff801647f46ae7d4feba73024302c318626bd92f Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 28 Nov 2022 11:29:42 +0100 Subject: [PATCH 17/19] Test deserializing all integer types --- src/de/mod.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/src/de/mod.rs b/src/de/mod.rs index 61e740b78..78bf4039e 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1099,14 +1099,96 @@ mod tests { #[test] fn numbered_key_maps() { use std::collections::BTreeMap; - let mut ranking: BTreeMap = BTreeMap::new(); + + // u8 + let mut ranking: BTreeMap = BTreeMap::new(); + ranking.insert(1, "Elon".to_string()); + ranking.insert(2, "Bazos".to_string()); + assert_eq!( + from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), + ranking + ); + + // u16 + let mut ranking: BTreeMap = BTreeMap::new(); + ranking.insert(1, "Elon".to_string()); + ranking.insert(2, "Bazos".to_string()); + assert_eq!( + from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), + ranking + ); + + // u32 + let mut ranking: BTreeMap = BTreeMap::new(); ranking.insert(1, "Elon".to_string()); ranking.insert(2, "Bazos".to_string()); + assert_eq!( + from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), + ranking + ); + // u64 + let mut ranking: BTreeMap = BTreeMap::new(); + ranking.insert(1, "Elon".to_string()); + ranking.insert(2, "Bazos".to_string()); assert_eq!( from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), ranking ); + + // u128 + let mut ranking: BTreeMap = BTreeMap::new(); + ranking.insert(1, "Elon".to_string()); + ranking.insert(2, "Bazos".to_string()); + assert_eq!( + from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), + ranking + ); + + // i8 + let mut ranking: BTreeMap = BTreeMap::new(); + ranking.insert(1, "Elon".to_string()); + ranking.insert(2, "Bazos".to_string()); + assert_eq!( + from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), + ranking + ); + + // i16 + let mut ranking: BTreeMap = BTreeMap::new(); + ranking.insert(1, "Elon".to_string()); + ranking.insert(2, "Bazos".to_string()); + assert_eq!( + from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), + ranking + ); + + // i32 + let mut ranking: BTreeMap = BTreeMap::new(); + ranking.insert(1, "Elon".to_string()); + ranking.insert(2, "Bazos".to_string()); + assert_eq!( + from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), + ranking + ); + + // i64 + let mut ranking: BTreeMap = BTreeMap::new(); + ranking.insert(1, "Elon".to_string()); + ranking.insert(2, "Bazos".to_string()); + assert_eq!( + from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), + ranking + ); + + // i128 + let mut ranking: BTreeMap = BTreeMap::new(); + ranking.insert(1, "Elon".to_string()); + ranking.insert(2, "Bazos".to_string()); + assert_eq!( + from_str::>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(), + ranking + ); } #[test] From 761cf3d46e66cd4f0d96108cb9082af1f40a0fda Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 28 Nov 2022 11:41:12 +0100 Subject: [PATCH 18/19] Test unit element type --- src/ser/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 8490157b8..cce6a28b6 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -990,9 +990,15 @@ mod tests { #[test] fn btree_map() { use std::collections::BTreeMap; + // empty map assert_eq!(to_string(&BTreeMap::<(), ()>::new()).unwrap(), r#"{}"#); + // One element with unit type + let mut map = BTreeMap::<&str, ()>::new(); + map.insert("set_element", ()); + assert_eq!(to_string(&map).unwrap(), r#"{"set_element":null}"#); + let mut two_values = BTreeMap::new(); two_values.insert("my_name", "joseph"); two_values.insert("her_name", "aline"); From 19ea90ceea697e5b4a2dcfc1b739d65b8f85cb19 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Mon, 28 Nov 2022 11:41:21 +0100 Subject: [PATCH 19/19] Test map_serialization_matches_json_serde --- src/ser/mod.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index cce6a28b6..98a280b51 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -1061,6 +1061,48 @@ mod tests { ); } + #[test] + fn map_serialization_matches_json_serde() { + use std::collections::BTreeMap; + + fn ser_actual(value: &T) -> String { + to_string(value).unwrap() + } + + fn ser_expected(value: &T) -> String { + serde_json::to_string(value).unwrap() + } + + let map = BTreeMap::<(), ()>::new(); + assert_eq!(ser_actual(&map), ser_expected(&map)); + + let mut two_values = BTreeMap::new(); + two_values.insert("my_name", "joseph"); + two_values.insert("her_name", "aline"); + assert_eq!(ser_actual(&two_values), ser_expected(&two_values)); + + let mut nested_map = BTreeMap::new(); + nested_map.insert("two_entries", two_values.clone()); + two_values.remove("my_name"); + nested_map.insert("one_entry", two_values); + assert_eq!(ser_actual(&nested_map), ser_expected(&nested_map)); + + // One element with unit type + let mut map = BTreeMap::<&str, ()>::new(); + map.insert("set_element", ()); + assert_eq!(ser_actual(&map), ser_expected(&map)); + + // numeric keys + let mut map = BTreeMap::new(); + map.insert(10i8, "my_age"); + assert_eq!(ser_actual(&map), ser_expected(&map)); + + // numeric values + let mut scores = BTreeMap::new(); + scores.insert("player A", 1234212); + assert_eq!(ser_actual(&scores), ser_expected(&scores)); + } + #[test] fn number_key() { use std::collections::HashMap;