Skip to content

Commit

Permalink
Merge branch 'CyberHoward/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
webmaster128 committed Nov 28, 2022
2 parents 1c20872 + 19ea90c commit 210fbf9
Show file tree
Hide file tree
Showing 7 changed files with 722 additions and 55 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ project adheres to [Semantic Versioning](http://semver.org/).

## Unreleased

### Added

- Add support for map (de)serialization.

### Changed

- Bump min supported Rust version to 1.59.0 (same as cosmwasm-std)
Expand Down
104 changes: 84 additions & 20 deletions src/de/map.rs
Original file line number Diff line number Diff line change
@@ -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>,
Expand All @@ -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;

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

fn deserialize_i8<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
unreachable!()
deserialize_signed_key!(self, visitor, i8, visit_i8)
}

fn deserialize_i16<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
unreachable!()
deserialize_signed_key!(self, visitor, i16, visit_i16)
}

fn deserialize_i32<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
unreachable!()
deserialize_signed_key!(self, visitor, i32, visit_i32)
}

fn deserialize_i64<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
unreachable!()
deserialize_signed_key!(self, visitor, i64, visit_i64)
}

fn deserialize_u8<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
unreachable!()
// default implementation includes string unparsing
self.de.deserialize_i128(visitor)
}

fn deserialize_u16<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
unreachable!()
deserialize_unsigned_key!(self, visitor, u8, visit_u8)
}

fn deserialize_u32<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
unreachable!()
deserialize_unsigned_key!(self, visitor, u16, visit_u16)
}

fn deserialize_u64<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
unreachable!()
deserialize_unsigned_key!(self, visitor, u32, visit_u32)
}

fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
deserialize_unsigned_key!(self, visitor, u64, visit_u64)
}

fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.de.deserialize_u128(visitor)
}

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

fn deserialize_string<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
unreachable!()
self.de.deserialize_string(visitor)
}

fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
Expand Down
126 changes: 110 additions & 16 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -576,22 +578,7 @@ 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<V>(self, _visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
unreachable!()
}

fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
Expand All @@ -610,6 +597,18 @@ impl<'a, 'de> de::Deserializer<'de> for &'a mut Deserializer<'de> {
}
}

fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_map(visitor)
}

fn deserialize_enum<V>(
self,
_name: &'static str,
Expand Down Expand Up @@ -1097,6 +1096,101 @@ mod tests {
);
}

#[test]
fn numbered_key_maps() {
use std::collections::BTreeMap;

// u8
let mut ranking: BTreeMap<u8, String> = BTreeMap::new();
ranking.insert(1, "Elon".to_string());
ranking.insert(2, "Bazos".to_string());
assert_eq!(
from_str::<BTreeMap<u8, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
ranking
);

// u16
let mut ranking: BTreeMap<u16, String> = BTreeMap::new();
ranking.insert(1, "Elon".to_string());
ranking.insert(2, "Bazos".to_string());
assert_eq!(
from_str::<BTreeMap<u16, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
ranking
);

// u32
let mut ranking: BTreeMap<u32, String> = BTreeMap::new();
ranking.insert(1, "Elon".to_string());
ranking.insert(2, "Bazos".to_string());
assert_eq!(
from_str::<BTreeMap<u32, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
ranking
);

// u64
let mut ranking: BTreeMap<u64, String> = BTreeMap::new();
ranking.insert(1, "Elon".to_string());
ranking.insert(2, "Bazos".to_string());
assert_eq!(
from_str::<BTreeMap<u64, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
ranking
);

// u128
let mut ranking: BTreeMap<u128, String> = BTreeMap::new();
ranking.insert(1, "Elon".to_string());
ranking.insert(2, "Bazos".to_string());
assert_eq!(
from_str::<BTreeMap<u128, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
ranking
);

// i8
let mut ranking: BTreeMap<i8, String> = BTreeMap::new();
ranking.insert(1, "Elon".to_string());
ranking.insert(2, "Bazos".to_string());
assert_eq!(
from_str::<BTreeMap<i8, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
ranking
);

// i16
let mut ranking: BTreeMap<i16, String> = BTreeMap::new();
ranking.insert(1, "Elon".to_string());
ranking.insert(2, "Bazos".to_string());
assert_eq!(
from_str::<BTreeMap<i16, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
ranking
);

// i32
let mut ranking: BTreeMap<i32, String> = BTreeMap::new();
ranking.insert(1, "Elon".to_string());
ranking.insert(2, "Bazos".to_string());
assert_eq!(
from_str::<BTreeMap<i32, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
ranking
);

// i64
let mut ranking: BTreeMap<i64, String> = BTreeMap::new();
ranking.insert(1, "Elon".to_string());
ranking.insert(2, "Bazos".to_string());
assert_eq!(
from_str::<BTreeMap<i64, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
ranking
);

// i128
let mut ranking: BTreeMap<i128, String> = BTreeMap::new();
ranking.insert(1, "Elon".to_string());
ranking.insert(2, "Bazos".to_string());
assert_eq!(
from_str::<BTreeMap<i128, String>>(r#"{"1": "Elon", "2": "Bazos"}"#).unwrap(),
ranking
);
}

#[test]
fn deserialize_optional_vector() {
#[derive(Debug, Deserialize, PartialEq)]
Expand Down
11 changes: 11 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -95,6 +97,7 @@ mod test {
published: bool,
comments: Vec<CommentId>,
stats: Stats,
balances: BTreeMap<String, u16>,
}

#[test]
Expand All @@ -107,7 +110,10 @@ mod test {
published: false,
comments: vec![],
stats: Stats { views: 0, score: 0 },
balances: BTreeMap::new(),
};
let mut balances: BTreeMap<String, u16> = BTreeMap::new();
balances.insert("chareen".into(), 347);
let max = Item {
model: Model::Post {
category: "fun".to_string(),
Expand All @@ -122,6 +128,7 @@ mod test {
views: std::u64::MAX,
score: std::i64::MIN,
},
balances,
};

// binary
Expand Down Expand Up @@ -172,6 +179,9 @@ mod test {
author: Address("[email protected]".to_owned()),
});

let mut balances: BTreeMap<String, u16> = BTreeMap::new();
balances.insert("chareen".into(), 347);

let item = ModelOrItem::Item(Item {
model: Model::Comment,
title: "Title".to_owned(),
Expand All @@ -183,6 +193,7 @@ mod test {
views: 110,
score: 12,
},
balances,
});

assert_eq!(
Expand Down
Loading

0 comments on commit 210fbf9

Please sign in to comment.