Skip to content

Commit 210fbf9

Browse files
committed
Merge branch 'CyberHoward/main'
2 parents 1c20872 + 19ea90c commit 210fbf9

File tree

7 files changed

+722
-55
lines changed

7 files changed

+722
-55
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ project adheres to [Semantic Versioning](http://semver.org/).
77

88
## Unreleased
99

10+
### Added
11+
12+
- Add support for map (de)serialization.
13+
1014
### Changed
1115

1216
- Bump min supported Rust version to 1.59.0 (same as cosmwasm-std)

src/de/map.rs

Lines changed: 84 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
use serde::de::{self, Visitor};
2-
31
use crate::de::{Deserializer, Error};
2+
use serde::de::{self, Visitor};
43

54
pub struct MapAccess<'a, 'b> {
65
de: &'a mut Deserializer<'b>,
@@ -13,6 +12,56 @@ impl<'a, 'b> MapAccess<'a, 'b> {
1312
}
1413
}
1514

15+
macro_rules! deserialize_signed_key {
16+
($self:ident, $visitor:ident, $ixx:ident, $visit_ixx:ident) => {{
17+
let de = $self.de;
18+
match de.parse_whitespace().ok_or(Error::EofWhileParsingValue)? {
19+
b'"' => de.eat_char(),
20+
_ => return Err(Error::InvalidType),
21+
};
22+
23+
let result = match de.peek() {
24+
// after rust merged or-patterns feature, these two clause can be merged.
25+
// error[E0658]: or-patterns syntax is experimental
26+
Some(b'0'..=b'9') => super::deserialize_signed!(de, $visitor, $ixx, $visit_ixx),
27+
Some(b'-') => super::deserialize_signed!(de, $visitor, $ixx, $visit_ixx),
28+
_ => return Err(Error::InvalidType),
29+
};
30+
match de.peek() {
31+
Some(b'"') => {
32+
de.eat_char();
33+
result
34+
}
35+
_ => Err(Error::InvalidType),
36+
}
37+
}};
38+
}
39+
40+
macro_rules! deserialize_unsigned_key {
41+
($self:ident, $visitor:ident, $ixx:ident, $visit_ixx:ident) => {{
42+
let de = $self.de;
43+
match de.parse_whitespace().ok_or(Error::EofWhileParsingValue)? {
44+
b'"' => de.eat_char(),
45+
_ => return Err(Error::InvalidType),
46+
};
47+
48+
let result = match de.peek() {
49+
// after rust merged or-patterns feature, these two clause can be merged.
50+
// error[E0658]: or-patterns syntax is experimental
51+
Some(b'0'..=b'9') => super::deserialize_unsigned!(de, $visitor, $ixx, $visit_ixx),
52+
Some(b'-') => super::deserialize_unsigned!(de, $visitor, $ixx, $visit_ixx),
53+
_ => return Err(Error::InvalidType),
54+
};
55+
match de.peek() {
56+
Some(b'"') => {
57+
de.eat_char();
58+
result
59+
}
60+
_ => Err(Error::InvalidType),
61+
}
62+
}};
63+
}
64+
1665
impl<'a, 'de> de::MapAccess<'de> for MapAccess<'a, 'de> {
1766
type Error = Error;
1867

@@ -79,60 +128,75 @@ impl<'de, 'a> de::Deserializer<'de> for MapKey<'a, 'de> {
79128
unreachable!()
80129
}
81130

82-
fn deserialize_i8<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
131+
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
83132
where
84133
V: Visitor<'de>,
85134
{
86-
unreachable!()
135+
deserialize_signed_key!(self, visitor, i8, visit_i8)
87136
}
88137

89-
fn deserialize_i16<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
138+
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
90139
where
91140
V: Visitor<'de>,
92141
{
93-
unreachable!()
142+
deserialize_signed_key!(self, visitor, i16, visit_i16)
94143
}
95144

96-
fn deserialize_i32<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
145+
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
97146
where
98147
V: Visitor<'de>,
99148
{
100-
unreachable!()
149+
deserialize_signed_key!(self, visitor, i32, visit_i32)
101150
}
102151

103-
fn deserialize_i64<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
152+
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
104153
where
105154
V: Visitor<'de>,
106155
{
107-
unreachable!()
156+
deserialize_signed_key!(self, visitor, i64, visit_i64)
108157
}
109158

110-
fn deserialize_u8<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
159+
fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
111160
where
112161
V: Visitor<'de>,
113162
{
114-
unreachable!()
163+
// default implementation includes string unparsing
164+
self.de.deserialize_i128(visitor)
115165
}
116166

117-
fn deserialize_u16<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
167+
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
118168
where
119169
V: Visitor<'de>,
120170
{
121-
unreachable!()
171+
deserialize_unsigned_key!(self, visitor, u8, visit_u8)
122172
}
123173

124-
fn deserialize_u32<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
174+
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
125175
where
126176
V: Visitor<'de>,
127177
{
128-
unreachable!()
178+
deserialize_unsigned_key!(self, visitor, u16, visit_u16)
129179
}
130180

131-
fn deserialize_u64<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
181+
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
132182
where
133183
V: Visitor<'de>,
134184
{
135-
unreachable!()
185+
deserialize_unsigned_key!(self, visitor, u32, visit_u32)
186+
}
187+
188+
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
189+
where
190+
V: Visitor<'de>,
191+
{
192+
deserialize_unsigned_key!(self, visitor, u64, visit_u64)
193+
}
194+
195+
fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
196+
where
197+
V: Visitor<'de>,
198+
{
199+
self.de.deserialize_u128(visitor)
136200
}
137201

138202
fn deserialize_f32<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
@@ -163,11 +227,11 @@ impl<'de, 'a> de::Deserializer<'de> for MapKey<'a, 'de> {
163227
self.de.deserialize_str(visitor)
164228
}
165229

166-
fn deserialize_string<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
230+
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
167231
where
168232
V: Visitor<'de>,
169233
{
170-
unreachable!()
234+
self.de.deserialize_string(visitor)
171235
}
172236

173237
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, Self::Error>

src/de/mod.rs

Lines changed: 110 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ macro_rules! deserialize_unsigned {
203203
}
204204
}};
205205
}
206+
pub(crate) use deserialize_unsigned;
206207

207208
macro_rules! deserialize_signed {
208209
($self:ident, $visitor:ident, $ixx:ident, $visit_ixx:ident) => {{
@@ -245,6 +246,7 @@ macro_rules! deserialize_signed {
245246
}
246247
}};
247248
}
249+
pub(crate) use deserialize_signed;
248250

249251
impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
250252
type Error = Error;
@@ -576,22 +578,7 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
576578
self.deserialize_seq(visitor)
577579
}
578580

579-
/// Unsupported. Can’t make an arbitrary-sized map in no-std. Use a struct with a
580-
/// known format, or implement a custom map deserializer / visitor:
581-
/// https://serde.rs/deserialize-map.html
582-
fn deserialize_map<V>(self, _visitor: V) -> Result<V::Value>
583-
where
584-
V: Visitor<'de>,
585-
{
586-
unreachable!()
587-
}
588-
589-
fn deserialize_struct<V>(
590-
self,
591-
_name: &'static str,
592-
_fields: &'static [&'static str],
593-
visitor: V,
594-
) -> Result<V::Value>
581+
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
595582
where
596583
V: Visitor<'de>,
597584
{
@@ -610,6 +597,18 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
610597
}
611598
}
612599

600+
fn deserialize_struct<V>(
601+
self,
602+
_name: &'static str,
603+
_fields: &'static [&'static str],
604+
visitor: V,
605+
) -> Result<V::Value>
606+
where
607+
V: Visitor<'de>,
608+
{
609+
self.deserialize_map(visitor)
610+
}
611+
613612
fn deserialize_enum<V>(
614613
self,
615614
_name: &'static str,
@@ -1097,6 +1096,101 @@ mod tests {
10971096
);
10981097
}
10991098

1099+
#[test]
1100+
fn numbered_key_maps() {
1101+
use std::collections::BTreeMap;
1102+
1103+
// u8
1104+
let mut ranking: BTreeMap<u8, String> = BTreeMap::new();
1105+
ranking.insert(1, "Elon".to_string());
1106+
ranking.insert(2, "Bazos".to_string());
1107+
assert_eq!(
1108+
from_str::<BTreeMap<u8, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
1109+
ranking
1110+
);
1111+
1112+
// u16
1113+
let mut ranking: BTreeMap<u16, String> = BTreeMap::new();
1114+
ranking.insert(1, "Elon".to_string());
1115+
ranking.insert(2, "Bazos".to_string());
1116+
assert_eq!(
1117+
from_str::<BTreeMap<u16, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
1118+
ranking
1119+
);
1120+
1121+
// u32
1122+
let mut ranking: BTreeMap<u32, String> = BTreeMap::new();
1123+
ranking.insert(1, "Elon".to_string());
1124+
ranking.insert(2, "Bazos".to_string());
1125+
assert_eq!(
1126+
from_str::<BTreeMap<u32, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
1127+
ranking
1128+
);
1129+
1130+
// u64
1131+
let mut ranking: BTreeMap<u64, String> = BTreeMap::new();
1132+
ranking.insert(1, "Elon".to_string());
1133+
ranking.insert(2, "Bazos".to_string());
1134+
assert_eq!(
1135+
from_str::<BTreeMap<u64, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
1136+
ranking
1137+
);
1138+
1139+
// u128
1140+
let mut ranking: BTreeMap<u128, String> = BTreeMap::new();
1141+
ranking.insert(1, "Elon".to_string());
1142+
ranking.insert(2, "Bazos".to_string());
1143+
assert_eq!(
1144+
from_str::<BTreeMap<u128, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
1145+
ranking
1146+
);
1147+
1148+
// i8
1149+
let mut ranking: BTreeMap<i8, String> = BTreeMap::new();
1150+
ranking.insert(1, "Elon".to_string());
1151+
ranking.insert(2, "Bazos".to_string());
1152+
assert_eq!(
1153+
from_str::<BTreeMap<i8, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
1154+
ranking
1155+
);
1156+
1157+
// i16
1158+
let mut ranking: BTreeMap<i16, String> = BTreeMap::new();
1159+
ranking.insert(1, "Elon".to_string());
1160+
ranking.insert(2, "Bazos".to_string());
1161+
assert_eq!(
1162+
from_str::<BTreeMap<i16, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
1163+
ranking
1164+
);
1165+
1166+
// i32
1167+
let mut ranking: BTreeMap<i32, String> = BTreeMap::new();
1168+
ranking.insert(1, "Elon".to_string());
1169+
ranking.insert(2, "Bazos".to_string());
1170+
assert_eq!(
1171+
from_str::<BTreeMap<i32, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
1172+
ranking
1173+
);
1174+
1175+
// i64
1176+
let mut ranking: BTreeMap<i64, String> = BTreeMap::new();
1177+
ranking.insert(1, "Elon".to_string());
1178+
ranking.insert(2, "Bazos".to_string());
1179+
assert_eq!(
1180+
from_str::<BTreeMap<i64, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
1181+
ranking
1182+
);
1183+
1184+
// i128
1185+
let mut ranking: BTreeMap<i128, String> = BTreeMap::new();
1186+
ranking.insert(1, "Elon".to_string());
1187+
ranking.insert(2, "Bazos".to_string());
1188+
assert_eq!(
1189+
from_str::<BTreeMap<i128, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
1190+
ranking
1191+
);
1192+
}
1193+
11001194
#[test]
11011195
fn deserialize_optional_vector() {
11021196
#[derive(Debug, Deserialize, PartialEq)]

src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ pub use self::ser::{to_string, to_vec};
6565

6666
#[cfg(test)]
6767
mod test {
68+
use std::collections::BTreeMap;
69+
6870
use super::*;
6971
use serde_derive::{Deserialize, Serialize};
7072

@@ -95,6 +97,7 @@ mod test {
9597
published: bool,
9698
comments: Vec<CommentId>,
9799
stats: Stats,
100+
balances: BTreeMap<String, u16>,
98101
}
99102

100103
#[test]
@@ -107,7 +110,10 @@ mod test {
107110
published: false,
108111
comments: vec![],
109112
stats: Stats { views: 0, score: 0 },
113+
balances: BTreeMap::new(),
110114
};
115+
let mut balances: BTreeMap<String, u16> = BTreeMap::new();
116+
balances.insert("chareen".into(), 347);
111117
let max = Item {
112118
model: Model::Post {
113119
category: "fun".to_string(),
@@ -122,6 +128,7 @@ mod test {
122128
views: std::u64::MAX,
123129
score: std::i64::MIN,
124130
},
131+
balances,
125132
};
126133

127134
// binary
@@ -172,6 +179,9 @@ mod test {
172179
author: Address("[email protected]".to_owned()),
173180
});
174181

182+
let mut balances: BTreeMap<String, u16> = BTreeMap::new();
183+
balances.insert("chareen".into(), 347);
184+
175185
let item = ModelOrItem::Item(Item {
176186
model: Model::Comment,
177187
title: "Title".to_owned(),
@@ -183,6 +193,7 @@ mod test {
183193
views: 110,
184194
score: 12,
185195
},
196+
balances,
186197
});
187198

188199
assert_eq!(

0 commit comments

Comments
 (0)