summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Scott <sam@osohq.com>2021-06-09 15:32:07 -0400
committerGitHub <noreply@github.com>2021-06-09 15:32:07 -0400
commite369232e36d6fda5df3d2e533b2cdc5c5d2a23bb (patch)
treec04efbee5807cca63c99d96dbba8645f5b96bc99
parent5bfaa7aa9f38806436e15928917cbd841a61e0f2 (diff)
Support deserializing sequences to a hashmap with keys. (#51)
-rw-r--r--src/de/mod.rs20
-rw-r--r--src/de/parse.rs6
-rw-r--r--src/ser.rs4
-rw-r--r--tests/test_deserialize.rs17
-rw-r--r--tests/test_serialize.rs5
5 files changed, 44 insertions, 8 deletions
diff --git a/src/de/mod.rs b/src/de/mod.rs
index 62da6a5..c3f9e40 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -512,6 +512,11 @@ impl<'a> LevelDeserializer<'a> {
fn into_deserializer(self) -> Result<QsDeserializer<'a>> {
match self.0 {
Level::Nested(map) => Ok(QsDeserializer::with_map(map)),
+ Level::OrderedSeq(map) => Ok(QsDeserializer::with_map(
+ map.into_iter()
+ .map(|(k, v)| (Cow::Owned(k.to_string()), v))
+ .collect(),
+ )),
Level::Invalid(e) => Err(de::Error::custom(e)),
l => Err(de::Error::custom(format!(
"could not convert {:?} to \
@@ -598,6 +603,19 @@ impl<'de> de::Deserializer<'de> for LevelDeserializer<'de> {
}
}
+ /// given the hint that this is a map, will first
+ /// attempt to deserialize ordered sequences into a map
+ /// otherwise, follows the any code path
+ fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
+ where
+ V: de::Visitor<'de>,
+ {
+ match self.0 {
+ Level::OrderedSeq(_) => self.into_deserializer()?.deserialize_map(visitor),
+ _ => self.deserialize_any(visitor),
+ }
+ }
+
deserialize_primitive!(bool, deserialize_bool, visit_bool);
deserialize_primitive!(i8, deserialize_i8, visit_i8);
deserialize_primitive!(i16, deserialize_i16, visit_i16);
@@ -625,7 +643,7 @@ impl<'de> de::Deserializer<'de> for LevelDeserializer<'de> {
tuple
ignored_any
seq
- map
+ // map
}
}
diff --git a/src/de/parse.rs b/src/de/parse.rs
index 75ae134..a466e5a 100644
--- a/src/de/parse.rs
+++ b/src/de/parse.rs
@@ -80,8 +80,7 @@ impl<'a> Level<'a> {
if let Level::Sequence(ref mut seq) = *self {
seq.push(Level::Flat(value));
} else if let Level::Uninitialised = *self {
- let mut seq = Vec::new();
- seq.push(Level::Flat(value));
+ let seq = vec![Level::Flat(value)];
*self = Level::Sequence(seq);
} else {
*self = Level::Invalid(
@@ -306,8 +305,7 @@ impl<'a> Parser<'a> {
// First character is an integer, attempt to parse it as an integer key
b'0'..=b'9' => {
let key = self.parse_key(b']', true)?;
- let key =
- usize::from_str_radix(&key, 10).map_err(Error::from)?;
+ let key = key.parse().map_err(Error::from)?;
self.parse_ord_seq_value(key, node)?;
return Ok(true);
}
diff --git a/src/ser.rs b/src/ser.rs
index 654c889..c281614 100644
--- a/src/ser.rs
+++ b/src/ser.rs
@@ -126,9 +126,9 @@ impl<'a, W: 'a + Write> QsSerializer<'a, W> {
.map(replace_space)
.collect::<String>();
let key = if let Some(ref key) = self.key {
- format!("{}[{}]", key, newkey).into()
+ format!("{}[{}]", key, newkey)
} else {
- newkey.to_owned()
+ newkey
};
self.key = Some(Cow::Owned(key))
}
diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs
index a620828..097cc57 100644
--- a/tests/test_deserialize.rs
+++ b/tests/test_deserialize.rs
@@ -656,3 +656,20 @@ fn deserialize_map_with_unit_enum_keys() {
assert_eq!(test.point[&Operator::Gt], 123);
assert_eq!(test.point[&Operator::Lt], 321);
}
+
+#[test]
+fn deserialize_map_with_int_keys() {
+ #[derive(Debug, Deserialize)]
+ struct Mapping {
+ mapping: HashMap<u64, u64>,
+ }
+
+ let test: Mapping = serde_qs::from_str("mapping[1]=2&mapping[3]=4").unwrap();
+
+ assert_eq!(test.mapping.get(&1).cloned(), Some(2));
+ assert_eq!(test.mapping.get(&3).cloned(), Some(4));
+ assert_eq!(test.mapping.get(&2).cloned(), None);
+
+ serde_qs::from_str::<Mapping>("mapping[1]=2&mapping[1]=4")
+ .expect_err("should error with repeated key");
+}
diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs
index 94a8de8..ddb7277 100644
--- a/tests/test_serialize.rs
+++ b/tests/test_serialize.rs
@@ -197,5 +197,8 @@ fn serialize_hashmap_keys() {
.collect(),
};
let s = qs::to_string(&data).unwrap();
- assert!(s == "attrs[key+1%21]=val+1&attrs[key+2%21]=val+2" || s == "attrs[key+2%21]=val+2&attrs[key+1%21]=val+1");
+ assert!(
+ s == "attrs[key+1%21]=val+1&attrs[key+2%21]=val+2"
+ || s == "attrs[key+2%21]=val+2&attrs[key+1%21]=val+1"
+ );
}