summaryrefslogtreecommitdiff
path: root/src/de
diff options
context:
space:
mode:
authorSam Scott <sam.scott89@gmail.com>2017-05-21 12:57:05 +0100
committerSam Scott <sam.scott89@gmail.com>2017-05-21 12:57:05 +0100
commitcdfdac80ff65ffb1c18df3da1534ea652a63dd40 (patch)
tree2816f4df3514603b5181a97ea957f383a5d8aaec /src/de
parentba5e0b32b71f7f79915d671e64d19bf9f2bcf422 (diff)
Docs, API and panics.
Improved documentation, simpified the API coverage, and replaced panics with errors in most cases.
Diffstat (limited to 'src/de')
-rw-r--r--src/de/mod.rs183
-rw-r--r--src/de/parse.rs30
2 files changed, 154 insertions, 59 deletions
diff --git a/src/de/mod.rs b/src/de/mod.rs
index 94c66e1..0f3aa10 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -1,10 +1,49 @@
//! Deserialization support for querystrings.
+//! ### An overview of the design of `QsDeserializer`
+//!
+//! This code is designed to handle non-ordered query parameters. For example,
+//! `struct { a: Vec<u8>, b: String }` might be serialized as either
+//! `a[0]=1&a[1]=2&b=Hello or a[1]=2&b=Hello&a[0]=1`.
+//!
+//! In order to cover the latter case, we have two options: scan through the
+//! string each time we need to find a particular key - worst case O(n^2 )
+//! running time; or pre-parse the list into a map structure, and then
+//! deserialize the map.
+//!
+//! We opt for the latter. But a TODO is implement the first case, which could
+//! potentially be more desirable, especially when the keys are known to be in
+//! order.
+//!
+//! The `parse` module handles this step of deserializing a querystring into the
+//! map structure. This uses `rust_url::percent_encoding` to handle
+//! first converting the string.
+//!
+//! From here, there are two main `Deserializer` objects: `QsDeserializer` and
+//! `LevelDeserializer`.
+//!
+//! The former is the top-level deserializer which is effectively only capable
+//! of deserializing map-like objects (i.e. those with (key, value) pairs).
+//! Hence, structs, maps, and enums are supported at this level.
+//!
+//! Each key is a `String`, and deserialized from a `String`. The values are
+//! `Level` elements. This is a recursive structure which can either be a "flat
+//! value", i.e. just a string, or a sequence or map of these elements. This can
+//! be thought of as similar to the `serde_json::Value` enum.
+//!
+//! Each `Level` can be deserialized through `LevelDeserializer`. This will
+//! recursively call back to the top level `QsDeserializer`, or when `Level` is
+//! a flat value it will attempt to deserialize it to a primitive via
+//! `ParsableStringDeserializer`.
+
+
+
mod parse;
pub use de::parse::Config;
use data_encoding;
+use data_encoding::base64url as base64;
use serde::de;
use serde::de::IntoDeserializer;
@@ -122,7 +161,7 @@ pub struct QsDeserializer {
}
#[derive(Debug)]
-pub enum Level {
+enum Level {
Nested(BTreeMap<String, Level>),
Sequence(Vec<Level>),
Flat(String),
@@ -140,7 +179,7 @@ impl QsDeserializer {
/// Returns a new `QsDeserializer`.
fn with_config(config: &Config, input: &[u8]) -> Self {
let decoded = percent_encoding::percent_decode(input);
- parse::Parser::new(decoded, vec![], None, config.max_depth()).to_deserializer()
+ parse::Parser::new(decoded, vec![], None, config.max_depth()).as_deserializer()
}
}
@@ -148,10 +187,10 @@ impl QsDeserializer {
impl<'de> de::Deserializer<'de> for QsDeserializer {
type Error = Error;
- fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
+ fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
where V: de::Visitor<'de>,
{
- self.deserialize_map(visitor)
+ Err(Error::top_level("primitive"))
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
@@ -248,26 +287,14 @@ impl<'de> de::Deserializer<'de> for QsDeserializer {
bytes
byte_buf
unit_struct
- // seq
- // seq_fixed_size
- // newtype_struct
- // tuple_struct
- // struct
identifier
- // struct_field
- // tuple
- // enum
ignored_any
}
}
-// use serde::de::IntoDeserializer;
-// use serde::de::value::SeqDeserializer;
-
impl<'de> de::MapAccess<'de> for QsDeserializer {
type Error = Error;
-
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
where K: de::DeserializeSeed<'de>,
{
@@ -292,19 +319,67 @@ impl<'de> de::MapAccess<'de> for QsDeserializer {
impl<'de> de::EnumAccess<'de> for QsDeserializer {
type Error = Error;
- type Variant = LevelDeserializer;
+ type Variant = Self;
fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant)>
where V: de::DeserializeSeed<'de>
{
if let Some((key, value)) = self.iter.next() {
- Ok((seed.deserialize(ParsableStringDeserializer(key))?, LevelDeserializer(value)))
+ self.value = Some(value);
+ Ok((seed.deserialize(ParsableStringDeserializer(key))?, self))
} else {
Err(de::Error::custom("No more values"))
}
}
}
+impl<'de> de::VariantAccess<'de> for QsDeserializer {
+ type Error = Error;
+ fn unit_variant(self) -> Result<()> {
+ Ok(())
+ }
+
+ fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
+ where
+ T: de::DeserializeSeed<'de>
+ {
+ if let Some(value) = self.value {
+ seed.deserialize(LevelDeserializer(value))
+ } else {
+ Err(de::Error::custom("no value to deserialize"))
+ }
+
+ }
+ fn tuple_variant<V>(
+ self,
+ _len: usize,
+ visitor: V
+ ) -> Result<V::Value>
+ where
+ V: de::Visitor<'de>
+ {
+ if let Some(value) = self.value {
+ de::Deserializer::deserialize_seq(LevelDeserializer(value), visitor)
+ } else {
+ Err(de::Error::custom("no value to deserialize"))
+ }
+ }
+ fn struct_variant<V>(
+ self,
+ _fields: &'static [&'static str],
+ visitor: V
+ ) -> Result<V::Value>
+ where
+ V: de::Visitor<'de>
+ {
+ if let Some(value) = self.value {
+ de::Deserializer::deserialize_map(LevelDeserializer(value), visitor)
+ } else {
+ Err(de::Error::custom("no value to deserialize"))
+ }
+ }
+}
+
impl<'de> de::EnumAccess<'de> for LevelDeserializer {
type Error = Error;
type Variant = Self;
@@ -314,10 +389,11 @@ impl<'de> de::EnumAccess<'de> for LevelDeserializer {
{
match self.0 {
Level::Flat(x) => {
- Ok((seed.deserialize(ParsableStringDeserializer(x))?, LevelDeserializer(Level::Invalid(""))))
+ Ok((seed.deserialize(ParsableStringDeserializer(x))?,
+ LevelDeserializer(Level::Invalid("this value can only deserialize to a UnitVariant"))))
},
_ => {
- Err(de::Error::custom("should not be here..."))
+ Err(de::Error::custom("this value can only deserialize to a UnitVariant"))
}
}
}
@@ -376,7 +452,7 @@ impl<'de, I: Iterator<Item=Level>> de::SeqAccess<'de> for LevelSeq<I> {
-pub struct LevelDeserializer(Level);
+struct LevelDeserializer(Level);
macro_rules! deserialize_primitive {
($ty:ident, $method:ident, $visit_method:ident) => (
@@ -404,7 +480,7 @@ macro_rules! deserialize_primitive {
}
impl LevelDeserializer {
- fn to_deserializer(self) -> Result<QsDeserializer> {
+ fn into_deserializer(self) -> Result<QsDeserializer> {
match self.0 {
Level::Nested(map) => {
Ok(QsDeserializer::with_map(map))
@@ -427,7 +503,6 @@ impl<'de> de::Deserializer<'de> for LevelDeserializer {
{
match self.0 {
Level::Nested(_) => {
- // QsDeserializer::with_map(map).deserialize_map(visitor)
self.deserialize_map(visitor)
},
Level::Sequence(_) => {
@@ -499,7 +574,7 @@ impl<'de> de::Deserializer<'de> for LevelDeserializer {
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
where V: de::Visitor<'de>,
{
- self.to_deserializer()?.deserialize_map(visitor)
+ self.into_deserializer()?.deserialize_map(visitor)
}
@@ -510,7 +585,7 @@ impl<'de> de::Deserializer<'de> for LevelDeserializer {
-> Result<V::Value>
where V: de::Visitor<'de>,
{
- self.to_deserializer()?.deserialize_struct(name, fields, visitor)
+ self.into_deserializer()?.deserialize_struct(name, fields, visitor)
}
fn deserialize_newtype_struct<V>(
@@ -530,7 +605,6 @@ impl<'de> de::Deserializer<'de> for LevelDeserializer {
) -> Result<V::Value>
where V: de::Visitor<'de>
{
- // self.to_deserializer()?.deserialize_tuple(len, visitor)
self.deserialize_seq(visitor)
}
@@ -545,6 +619,44 @@ impl<'de> de::Deserializer<'de> for LevelDeserializer {
self.deserialize_seq(visitor)
}
+ fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
+ where V: de::Visitor<'de>
+ {
+ match self.0 {
+ Level::Nested(_) => {
+ Err(de::Error::custom("Expected: base64-encoded string, got a Map"))
+ },
+ Level::Sequence(_) => {
+ Err(de::Error::custom("Expected: base64-encoded string, got a Sequence"))
+ },
+ Level::Flat(x) => {
+ visitor.visit_byte_buf(base64::decode_nopad(x.as_bytes())?)
+ },
+ Level::Invalid(e) => {
+ Err(de::Error::custom(e))
+ }
+ }
+ }
+
+ fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
+ where V: de::Visitor<'de>
+ {
+ match self.0 {
+ Level::Nested(_) => {
+ Err(de::Error::custom("Expected: base64-encoded string, got a Map"))
+ },
+ Level::Sequence(_) => {
+ Err(de::Error::custom("Expected: base64-encoded string, got a Sequence"))
+ },
+ Level::Flat(x) => {
+ visitor.visit_byte_buf(base64::decode_nopad(x.as_bytes())?)
+ },
+ Level::Invalid(e) => {
+ Err(de::Error::custom(e))
+ }
+ }
+ }
+
deserialize_primitive!(bool, deserialize_bool, visit_bool);
deserialize_primitive!(i8, deserialize_i8, visit_i8);
deserialize_primitive!(i16, deserialize_i16, visit_i16);
@@ -563,14 +675,8 @@ impl<'de> de::Deserializer<'de> for LevelDeserializer {
str
string
unit
- bytes
- byte_buf
unit_struct
- // newtype_struct
- // tuple_struct
identifier
- // tuple
- // enum
ignored_any
}
}
@@ -590,7 +696,7 @@ macro_rules! forward_parsable_to_deserialize_any {
}
-pub struct ParsableStringDeserializer(String);
+struct ParsableStringDeserializer(String);
impl<'de> de::Deserializer<'de> for ParsableStringDeserializer {
type Error = Error;
@@ -603,17 +709,6 @@ impl<'de> de::Deserializer<'de> for ParsableStringDeserializer {
forward_to_deserialize_any! {
- // bool
- // u8
- // u16
- // u32
- // u64
- // i8
- // i16
- // i32
- // i64
- // f32
- // f64
map
struct
seq
diff --git a/src/de/parse.rs b/src/de/parse.rs
index 1f91f07..1d5e5a8 100644
--- a/src/de/parse.rs
+++ b/src/de/parse.rs
@@ -13,7 +13,7 @@ use super::*;
/// The default value for `max_depth` is 5.
///
/// ```
-/// use serde_qs::de::Config;
+/// use serde_qs::Config;
/// use std::collections::HashMap;
///
/// let config = Config::with_max_depth(0);
@@ -131,7 +131,7 @@ impl<I: Iterator<Item = u8>> Parser<I> {
}
}
- pub fn to_deserializer(mut self) -> QsDeserializer {
+ pub fn as_deserializer(&mut self) -> QsDeserializer {
let map = BTreeMap::default();
let mut root = Level::Nested(map);
while let Ok(x) = self.parse(&mut root) {
@@ -141,7 +141,7 @@ impl<I: Iterator<Item = u8>> Parser<I> {
}
let iter = match root {
Level::Nested(map) => map.into_iter(),
- _ => panic!(""),
+ _ => panic!("root node should never be able to converted to anything else. Something went seriously wrong."),
};
QsDeserializer {
iter: iter,
@@ -238,7 +238,7 @@ impl<I: Iterator<Item = u8>> Parser<I> {
}
}
let value = String::from_utf8(self.acc.split_off(0));
- let value = value.map_err(|e| ErrorKind::Utf8(e))?;
+ let value = value.map_err(Error::from)?;
// Reached the end of the key string
insert_into_map(node, key, value);
Ok(())
@@ -263,7 +263,7 @@ impl<I: Iterator<Item = u8>> Parser<I> {
}
},
_ => {
- panic!("Unexpected character");
+ Err(de::Error::custom("Unexpected character found when parsing"))
},
}
} else {
@@ -281,7 +281,7 @@ impl<I: Iterator<Item = u8>> Parser<I> {
}
let value = String::from_utf8(self.acc.split_off(0))
.map(|s| s.into());
- let value = value.map_err(|e| ErrorKind::Utf8(e))?;
+ let value = value.map_err(Error::from)?;
// Reached the end of the key string
if let Level::Sequence(ref mut seq) = *node {
seq.push(Level::Flat(value));
@@ -300,7 +300,7 @@ impl<I: Iterator<Item = u8>> Parser<I> {
}
- pub fn parse(&mut self, node: &mut Level) -> Result<bool> {
+ fn parse(&mut self, node: &mut Level) -> Result<bool> {
// First character determines parsing type
if self.depth == 0 {
let key = self.parse_key(b'\x00', true)?;
@@ -317,7 +317,7 @@ impl<I: Iterator<Item = u8>> Parser<I> {
match tu!(self.peek()) {
// key is of the form "[...", not really allowed.
b'[' => {
- panic!("");
+ Err(de::Error::custom("found another opening bracket before the closed bracket"))
},
// key is simply "[]", so treat as a seq.
@@ -329,29 +329,29 @@ impl<I: Iterator<Item = u8>> Parser<I> {
},
// Key is "[a..." so parse up to the closing "]"
- 0x20...0x7e => {
+ 0x20...0x5a | 0x5c | 0x5e...0x7e => {
let key = self.parse_key(b']', true)?;
self.parse_map_value(key.into(), node)?;
self.depth += 1;
Ok(true)
},
- _ => {
- panic!("");
+ c => {
+ Err(de::Error::custom(format!("unexpected character: {}", c)))
},
}
},
// This means the key should be a root key
// of the form "abc" or "abc[...]"
- 0x20...0x7e => {
+ 0x20...0x5a | 0x5c...0x7e => {
let key = self.parse_key(b'[', false)?;
self.parse_map_value(key.into(), node)?;
self.depth += 1;
Ok(true)
},
- _ => {
- panic!("");
- },
+ c => {
+ Err(de::Error::custom(format!("unexpected character: {}", c)))
+ }
}
},
// Ran out of characters to parse