diff options
author | Sam Scott <sam.scott89@gmail.com> | 2017-05-21 12:57:05 +0100 |
---|---|---|
committer | Sam Scott <sam.scott89@gmail.com> | 2017-05-21 12:57:05 +0100 |
commit | cdfdac80ff65ffb1c18df3da1534ea652a63dd40 (patch) | |
tree | 2816f4df3514603b5181a97ea957f383a5d8aaec /src/de | |
parent | ba5e0b32b71f7f79915d671e64d19bf9f2bcf422 (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.rs | 183 | ||||
-rw-r--r-- | src/de/parse.rs | 30 |
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 |