summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Bihel <simon.bihel@spruceid.com>2023-06-12 16:53:06 +0100
committerSimon Bihel <simon.bihel@spruceid.com>2023-06-12 16:54:50 +0100
commit058781081b811b65bf14bf2b673de22d0761fbad (patch)
treedc8932b6e2ca0402ddc343aacee41f58cacb2faf
parent8a13b677f1b99ab78870f8731e75a7642f2d0530 (diff)
Add support for enums in top level
Partially address #71
-rw-r--r--src/de/mod.rs13
-rw-r--r--src/de/parse.rs4
-rw-r--r--tests/test_deserialize.rs45
3 files changed, 54 insertions, 8 deletions
diff --git a/src/de/mod.rs b/src/de/mod.rs
index ef9cd76..150f6fa 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -45,6 +45,7 @@ use serde::de::IntoDeserializer;
use std::borrow::Cow;
use std::collections::btree_map::{BTreeMap, Entry, IntoIter};
+use std::iter::Peekable;
/// To override the default serialization parameters, first construct a new
/// Config.
@@ -190,7 +191,7 @@ pub fn from_str<'de, T: de::Deserialize<'de>>(input: &'de str) -> Result<T> {
///
/// Supported top-level outputs are structs and maps.
pub(crate) struct QsDeserializer<'a> {
- iter: IntoIter<Cow<'a, str>, Level<'a>>,
+ iter: Peekable<IntoIter<Cow<'a, str>, Level<'a>>>,
value: Option<Level<'a>>,
}
@@ -207,7 +208,7 @@ enum Level<'a> {
impl<'a> QsDeserializer<'a> {
fn with_map(map: BTreeMap<Cow<'a, str>, Level<'a>>) -> Self {
QsDeserializer {
- iter: map.into_iter(),
+ iter: map.into_iter().peekable(),
value: None,
}
}
@@ -225,11 +226,11 @@ impl<'de> de::Deserializer<'de> for QsDeserializer<'de> {
where
V: de::Visitor<'de>,
{
- if self.iter.next().is_none() {
- return visitor.visit_unit();
+ if self.iter.peek().is_none() {
+ visitor.visit_unit()
+ } else {
+ self.deserialize_map(visitor)
}
-
- Err(Error::top_level("primitive"))
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
diff --git a/src/de/parse.rs b/src/de/parse.rs
index a76f2c5..0080d02 100644
--- a/src/de/parse.rs
+++ b/src/de/parse.rs
@@ -280,8 +280,8 @@ impl<'a> Parser<'a> {
// Parses all top level nodes into the `root` map.
while self.parse(&mut root)? {}
let iter = match root {
- Level::Nested(map) => map.into_iter(),
- _ => BTreeMap::default().into_iter(),
+ Level::Nested(map) => map.into_iter().peekable(),
+ _ => BTreeMap::default().into_iter().peekable(),
};
Ok(QsDeserializer { iter, value: None })
}
diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs
index cbe2019..12c4a8c 100644
--- a/tests/test_deserialize.rs
+++ b/tests/test_deserialize.rs
@@ -305,6 +305,51 @@ fn deserialize_enum_untagged() {
}
#[test]
+fn deserialize_enum_untagged_top_level() {
+ #[derive(Deserialize, Debug, PartialEq)]
+ #[serde(untagged)]
+ enum E {
+ B { b: String },
+ S { s: String },
+ }
+
+ let params = "s=true";
+ let rec_params: E = qs::from_str(params).unwrap();
+ assert_eq!(
+ rec_params,
+ E::S {
+ s: "true".to_string()
+ }
+ );
+ let params = "b=test";
+ let rec_params: E = qs::from_str(params).unwrap();
+ assert_eq!(
+ rec_params,
+ E::B {
+ b: "test".to_string()
+ }
+ );
+}
+
+#[test]
+fn deserialize_enum_top_level() {
+ #[derive(Deserialize, Debug, PartialEq)]
+ enum E {
+ B { b: String },
+ S { s: String },
+ }
+
+ let params = "S[s]=test";
+ let rec_params: E = qs::from_str(params).unwrap();
+ assert_eq!(
+ rec_params,
+ E::S {
+ s: "test".to_string()
+ }
+ );
+}
+
+#[test]
fn deserialize_enum_adjacently() {
#[derive(Deserialize, Debug, PartialEq)]
#[serde(tag = "type", content = "val")]