From 78c9f7eda88039bdc7e6c4003381ee125185880d Mon Sep 17 00:00:00 2001 From: Simon Bihel Date: Mon, 12 Jun 2023 16:53:06 +0100 Subject: [PATCH] Add support for enums in top level Partially address #71 --- src/de/mod.rs | 14 ++++++------ src/de/parse.rs | 4 ++-- tests/test_deserialize.rs | 45 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/de/mod.rs b/src/de/mod.rs index ef9cd76..7fed531 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -37,7 +37,6 @@ //! `ParsableStringDeserializer`. mod parse; - use crate::error::*; use serde::de; @@ -45,6 +44,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 +190,7 @@ pub fn from_str<'de, T: de::Deserialize<'de>>(input: &'de str) -> Result { /// /// Supported top-level outputs are structs and maps. pub(crate) struct QsDeserializer<'a> { - iter: IntoIter, Level<'a>>, + iter: Peekable, Level<'a>>>, value: Option>, } @@ -207,7 +207,7 @@ enum Level<'a> { impl<'a> QsDeserializer<'a> { fn with_map(map: BTreeMap, Level<'a>>) -> Self { QsDeserializer { - iter: map.into_iter(), + iter: map.into_iter().peekable(), value: None, } } @@ -225,11 +225,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(self, visitor: V) -> Result 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 @@ -304,6 +304,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)]