summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--examples/csv_vectors.rs10
-rw-r--r--examples/introduction.rs27
-rw-r--r--src/de.rs300
-rw-r--r--src/lib.rs53
-rw-r--r--src/ser/key.rs30
-rw-r--r--src/ser/mod.rs13
-rw-r--r--src/ser/part.rs16
-rw-r--r--src/ser/value.rs11
-rw-r--r--tests/test_deserialize.rs62
-rw-r--r--tests/test_serialize.rs8
11 files changed, 295 insertions, 237 deletions
diff --git a/README.md b/README.md
index 94075e0..371b618 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ when using nested parameters, similar to those used by [qs][qs] for Node, and
commonly used by Ruby on Rails via [Rake][Rake].
The core of the library is heavily adapted from
-[`application/x-www-form-urlencoded`][urlencoded], which should be preferred
+[`serde_urlencoded`][urlencoded], which should be preferred
over this crate whenever non-nested query parameters are sufficient. It is built
upon [Serde], a high performance generic serialization framework and [rust-url],
a URL parser for Rust.
diff --git a/examples/csv_vectors.rs b/examples/csv_vectors.rs
index 95e4398..39e95a1 100644
--- a/examples/csv_vectors.rs
+++ b/examples/csv_vectors.rs
@@ -19,7 +19,7 @@ fn main() {
fn from_csv<D>(deserializer: D) -> Result<Vec<u8>, D::Error>
- where D: serde::Deserializer
+ where D: serde::Deserializer,
{
deserializer.deserialize_str(CSVVecVisitor)
}
@@ -30,12 +30,14 @@ struct CSVVecVisitor;
impl serde::de::Visitor for CSVVecVisitor {
type Value = Vec<u8>;
- fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
+ fn expecting(&self,
+ formatter: &mut std::fmt::Formatter)
+ -> std::fmt::Result {
write!(formatter, "a str")
}
fn visit_str<E>(self, s: &str) -> std::result::Result<Self::Value, E>
- where E: serde::de::Error
+ where E: serde::de::Error,
{
let mut output = Vec::new();
let mut items = csv::Reader::from_string(s);
@@ -46,6 +48,4 @@ impl serde::de::Visitor for CSVVecVisitor {
Ok(output)
}
-
-
}
diff --git a/examples/introduction.rs b/examples/introduction.rs
index 9d949b4..66283d3 100644
--- a/examples/introduction.rs
+++ b/examples/introduction.rs
@@ -38,7 +38,7 @@ fn main() {
city: "Carrot City".to_string(),
postcode: "12345".to_string(),
},
- user_ids: vec!(1,2,3,4),
+ user_ids: vec![1, 2, 3, 4],
};
// Naive approach: manually parameters in a map. Painful.
@@ -80,19 +80,18 @@ fn main() {
let encoded2 = qs::to_string(&params).unwrap();
assert_eq!(encoded, encoded2);
- // An advantage of `serde_qs` for deserializing, is that it is robust against
- // different orderings of inputs:
+ // An advantage of `serde_qs` for deserializing, is that it is robust
+ // against different orderings of inputs:
- let mut inputs = vec!["id=42",
- "name=Acme",
- "phone=12345",
- "address[city]=Carrot+City",
- "address[postcode]=12345",
- "user_ids[0]=1",
- "user_ids[1]=2",
- "user_ids[2]=3",
- "user_ids[3]=4"
- ];
+ let mut inputs = vec!["id=42",
+ "name=Acme",
+ "phone=12345",
+ "address[city]=Carrot+City",
+ "address[postcode]=12345",
+ "user_ids[0]=1",
+ "user_ids[1]=2",
+ "user_ids[2]=3",
+ "user_ids[3]=4"];
let mut rng = rand::thread_rng();
for _ in 0..10 {
@@ -128,4 +127,4 @@ fn main() {
user_ids[512]=4";
let params: QueryParams = qs::from_str(encoded).unwrap();
assert_eq!(params, example_params);
-} \ No newline at end of file
+}
diff --git a/src/de.rs b/src/de.rs
index 418c494..3f3e9a0 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -1,44 +1,47 @@
//! Deserialization support for the `application/x-www-form-urlencoded` format.
use serde::de;
-
-use std::collections::btree_map::{BTreeMap, Entry, IntoIter};
#[doc(inline)]
pub use serde::de::value::Error;
use serde::de::value::MapDeserializer;
+
+use std::collections::btree_map::{BTreeMap, Entry, IntoIter};
use std::io::Read;
use url::percent_encoding;
-///
+///
pub struct Config {
max_depth: usize,
}
impl Default for Config {
fn default() -> Self {
- Config {
- max_depth: 6,
- }
+ Config { max_depth: 6 }
}
}
impl Config {
pub fn max_depth(&mut self, depth: usize) {
self.max_depth = depth;
- }
+ }
}
impl Config {
- pub fn from_bytes<T: de::Deserialize>(&self, input: &[u8]) -> Result<T, Error> {
+ pub fn from_bytes<T: de::Deserialize>(&self,
+ input: &[u8])
+ -> Result<T, Error> {
T::deserialize(Deserializer::with_config(self, input))
}
- pub fn from_str<T: de::Deserialize>(&self, input: &str) -> Result<T, Error> {
+ pub fn from_str<T: de::Deserialize>(&self,
+ input: &str)
+ -> Result<T, Error> {
self.from_bytes(input.as_bytes())
}
pub fn from_reader<T, R>(&self, mut reader: R) -> Result<T, Error>
- where T: de::Deserialize, R: Read
+ where T: de::Deserialize,
+ R: Read,
{
let mut buf = vec![];
reader.read_to_end(&mut buf)
@@ -60,18 +63,20 @@ impl Config {
/// struct Query {
/// name: String,
/// age: u8,
-/// occupation: String,
+/// occupation: String,
/// }
///
/// # fn main(){
/// let q = Query {
/// name: "Alice".to_owned(),
/// age: 24,
-/// occupation: "Student".to_owned(),
+/// occupation: "Student".to_owned(),
/// };
///
/// assert_eq!(
-/// serde_qs::from_bytes::<Query>("name=Alice&age=24&occupation=Student".as_bytes()),
+/// serde_qs::from_bytes::<Query>(
+/// "name=Alice&age=24&occupation=Student".as_bytes()
+/// ),
/// Ok(q));
/// # }
/// ```
@@ -89,14 +94,14 @@ pub fn from_bytes<T: de::Deserialize>(input: &[u8]) -> Result<T, Error> {
/// struct Query {
/// name: String,
/// age: u8,
-/// occupation: String,
+/// occupation: String,
/// }
///
/// # fn main(){
/// let q = Query {
/// name: "Alice".to_owned(),
/// age: 24,
-/// occupation: "Student".to_owned(),
+/// occupation: "Student".to_owned(),
/// };
///
/// assert_eq!(
@@ -111,7 +116,8 @@ pub fn from_str<T: de::Deserialize>(input: &str) -> Result<T, Error> {
/// Convenience function that reads all bytes from `reader` and deserializes
/// them with `from_bytes`.
pub fn from_reader<T, R>(mut reader: R) -> Result<T, Error>
- where T: de::Deserialize, R: Read
+ where T: de::Deserialize,
+ R: Read,
{
let mut buf = vec![];
reader.read_to_end(&mut buf)
@@ -141,24 +147,23 @@ macro_rules! tu {
($x:expr) => (
match $x {
Some(x) => x,
- // None => return Err(de::Error::custom("query string ended before expected"))
- None => panic!("None found here"),
+ None => return Err(
+ de::Error::custom("query string ended before expected"))
}
)
}
-use std::str;
use std::iter::Iterator;
+use std::str;
-struct Parser<I: Iterator<Item=u8>> {
+struct Parser<I: Iterator<Item = u8>> {
inner: I,
acc: Vec<u8>,
peeked: Option<u8>,
depth: usize,
}
-impl<I: Iterator<Item=u8>> Iterator for Parser<I>
-{
+impl<I: Iterator<Item = u8>> Iterator for Parser<I> {
type Item = u8;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
@@ -168,7 +173,6 @@ impl<I: Iterator<Item=u8>> Iterator for Parser<I>
fn insert_into_map(node: &mut Level, key: String, value: String) {
- // println!("({:?}, {:?})", key, value);
if let Level::Nested(ref mut map) = *node {
match map.entry(key) {
Entry::Occupied(mut o) => {
@@ -176,17 +180,16 @@ fn insert_into_map(node: &mut Level, key: String, value: String) {
},
Entry::Vacant(vm) => {
vm.insert(Level::Flat(value));
- }
+ },
}
} else {
- // println!("Removing uninitialised value");
let mut map = BTreeMap::default();
map.insert(key, Level::Flat(value));
*node = Level::Nested(map);
}
}
-impl<I: Iterator<Item=u8>> Parser<I> {
+impl<I: Iterator<Item = u8>> Parser<I> {
#[inline]
fn peek(&mut self) -> Option<<Self as Iterator>::Item> {
if !self.acc.is_empty() {
@@ -202,11 +205,14 @@ impl<I: Iterator<Item=u8>> Parser<I> {
}
}
- fn parse_key(&mut self, end_on: u8, consume: bool) -> Result<String, Error> {
+ fn parse_key(&mut self,
+ end_on: u8,
+ consume: bool)
+ -> Result<String, Error> {
loop {
if let Some(x) = self.next() {
- match x {
- x if x == end_on => {
+ match x {
+ x if x == end_on => {
let res = String::from_utf8(self.acc.split_off(0));
self.acc.clear();
@@ -215,7 +221,7 @@ impl<I: Iterator<Item=u8>> Parser<I> {
self.acc.push(x);
self.peeked = Some(x);
}
- return res.map_err(|_| de::Error::custom("blah"))
+ return res.map_err(|_| de::Error::custom("blah"));
},
b'=' => {
// Allow the '=' byte when parsing keys within []
@@ -229,38 +235,42 @@ impl<I: Iterator<Item=u8>> Parser<I> {
self.acc.push(b'=');
self.peeked = Some(b'=');
- return res.map_err(|_| de::Error::custom("blah"))
+ return res.map_err(|_| de::Error::custom("blah"));
}
- }
+ },
b' ' => {
self.acc.push(b' ');
- }
+ },
b'&' => {
let res = String::from_utf8(self.acc.split_off(0));
self.acc.clear();
self.acc.push(b'&');
self.peeked = Some(b'&');
- return res.map_err(|_| de::Error::custom("blah"))
- }
- x @ 0x20 ... 0x7e => {
+ return res.map_err(|_| de::Error::custom("blah"));
+ },
+ x @ 0x20...0x7e => {
self.acc.push(x);
},
_ => {
- return Err(de::Error::custom("unexpected character in query string."));
- }
+ return Err(de::Error::custom("unexpected character \
+ in query string."));
+ },
}
} else {
// End of string.
let res = String::from_utf8(self.acc.split_off(0));
self.acc.clear();
- return res.map_err(|_| de::Error::custom("blah"))
+ return res.map_err(|_| de::Error::custom("blah"));
}
}
}
- fn parse_map_value(&mut self, key: String, node: &mut Level) -> Result<(), Error> {
+ fn parse_map_value(&mut self,
+ key: String,
+ node: &mut Level)
+ -> Result<(), Error> {
if let Some(x) = self.peek() {
- match x {
+ match x {
b'=' => {
self.acc.clear();
for b in self.inner.by_ref().take_while(|b| b != &b'&') {
@@ -279,27 +289,25 @@ impl<I: Iterator<Item=u8>> Parser<I> {
b'&' => {
insert_into_map(node, key, "".to_string());
Ok(())
- }
+ },
b'[' => {
if let Level::Invalid(_) = *node {
*node = Level::Nested(BTreeMap::default());
}
-
- // Ok(())
if let Level::Nested(ref mut map) = *node {
self.depth -= 1;
- // println!("Possibly adding uninitialised value for {}", key);
- self.parse(
- map.entry(key).or_insert(Level::Invalid("uninitialised"))
- )?;
+ self.parse(map.entry(key)
+ .or_insert(Level::Invalid("uninitialised")))?;
Ok(())
} else {
- Err(de::Error::custom(format!("tried to insert a new key into {:?}", node)))
+ Err(de::Error::custom(format!("tried to insert a \
+ new key into {:?}",
+ node)))
}
- }
+ },
_ => {
panic!("Unexpected character");
- }
+ },
}
} else {
insert_into_map(node, key, "".to_string());
@@ -308,17 +316,16 @@ impl<I: Iterator<Item=u8>> Parser<I> {
}
fn parse_seq_value(&mut self, node: &mut Level) -> Result<(), Error> {
- // println!("Adding as a sequence value.");
match tu!(self.peek()) {
b'=' => {
self.acc.clear();
- // let value = str::from_utf8(input.take_while(|b| *b != &b'&').collect());
- // self.acc.extend_from_slice(&self.take_while(|b| *b != &b'&').collect());
for b in self.inner.by_ref().take_while(|b| b != &b'&') {
self.acc.push(b);
}
- let value = String::from_utf8(self.acc.split_off(0)).map(|s| s.into());
- let value = value.map_err(|e| de::Error::custom(e.to_string()))?;
+ let value = String::from_utf8(self.acc.split_off(0))
+ .map(|s| s.into());
+ let value =
+ value.map_err(|e| de::Error::custom(e.to_string()))?;
// Reached the end of the key string
if let Level::Sequence(ref mut seq) = *node {
seq.push(Level::Flat(value));
@@ -330,8 +337,9 @@ impl<I: Iterator<Item=u8>> Parser<I> {
Ok(())
},
_ => {
- Err(de::Error::custom("non-indexed sequence of structs not supported"))
- }
+ Err(de::Error::custom("non-indexed sequence of structs not \
+ supported"))
+ },
}
}
@@ -345,61 +353,63 @@ impl<I: Iterator<Item=u8>> Parser<I> {
return Ok(true);
}
match self.peek() {
- Some(x) => match x {
- b'[' => {
- self.acc.clear();
- // let _ = self.next();
- match tu!(self.peek()) {
- // key is of the form "[...", not really allowed.
- b'[' => {
- panic!("");
-
- },
- // key is simply "[]", so treat as a seq.
- b']' => {
- self.acc.clear();
- // println!("Empty key => vector");
- // println!("{:?}", node);
- self.parse_seq_value(node)?;
- self.depth += 1;
- Ok(true)
-
- },
- // Key is "[a..." so parse up to the closing "]"
- 0x20 ... 0x7e => {
- let key = self.parse_key(b']', true).unwrap();
- // key.into()
- // println!("key: {:?}", key);
- self.parse_map_value(key.into(), node)?;
- self.depth += 1;
- Ok(true)
-
- },
- _ => {
- panic!("");
+ Some(x) => {
+ match x {
+ b'[' => {
+ self.acc.clear();
+ // let _ = self.next();
+ match tu!(self.peek()) {
+ // key is of the form "[...", not really allowed.
+ b'[' => {
+ panic!("");
+
+ },
+ // key is simply "[]", so treat as a seq.
+ b']' => {
+ self.acc.clear();
+ // println!("Empty key => vector");
+ // println!("{:?}", node);
+ self.parse_seq_value(node)?;
+ self.depth += 1;
+ Ok(true)
+
+ },
+ // Key is "[a..." so parse up to the closing "]"
+ 0x20...0x7e => {
+ let key = self.parse_key(b']', true).unwrap();
+ // key.into()
+ // println!("key: {:?}", key);
+ self.parse_map_value(key.into(), node)?;
+ self.depth += 1;
+ Ok(true)
+
+ },
+ _ => {
+ panic!("");
+ },
}
- }
- },
- // This means the key should be a root key of the form "abc" or "abc[...]"
- 0x20 ... 0x7e => {
- let key = self.parse_key(b'[', false).unwrap();
- self.parse_map_value(key.into(), node)?;
- self.depth += 1;
- Ok(true)
- },
- _ => {
- panic!("");
+ },
+ // This means the key should be a root key
+ // of the form "abc" or "abc[...]"
+ 0x20...0x7e => {
+ let key = self.parse_key(b'[', false).unwrap();
+ self.parse_map_value(key.into(), node)?;
+ self.depth += 1;
+ Ok(true)
+ },
+ _ => {
+ panic!("");
+ },
}
},
// Ran out of characters to parse
- None => Ok(false)
+ None => Ok(false),
}
}
-
}
impl Deserializer {
- fn with_map(map: BTreeMap<String,Level>) -> Self {
+ fn with_map(map: BTreeMap<String, Level>) -> Self {
Deserializer {
iter: map.into_iter(),
value: None,
@@ -421,44 +431,18 @@ impl Deserializer {
while let Ok(x) = parser.parse(&mut root) {
if !x {
- break
+ break;
}
}
- // self.input = Some(decoded.as_bytes());
- // println!("{:?}", root);
let iter = match root {
Level::Nested(map) => map.into_iter(),
_ => panic!(""),
};
- Deserializer {
+ Deserializer {
iter: iter,
value: None,
}
}
-
- // /// Returns a new `Deserializer`.
- // pub fn new(input: &[u8]) -> Self {
- // let map = BTreeMap::default();
- // let mut root = Level::Nested(map);
-
- // let decoded = percent_encoding::percent_decode(&input);
- // let mut parser = Parser::new(decoded);
- // while let Ok(x) = parser.parse(&mut root) {
- // if !x {
- // break
- // }
- // }
- // // self.input = Some(decoded.as_bytes());
- // // println!("{:?}", root);
- // let iter = match root {
- // Level::Nested(map) => map.into_iter(),
- // _ => panic!(""),
- // };
- // Deserializer {
- // iter: iter,
- // value: None,
- // }
- // }
}
impl de::Deserializer for Deserializer {
@@ -476,19 +460,18 @@ impl de::Deserializer for Deserializer {
visitor.visit_map(self)
}
- // _serde::Deserializer::deserialize_struct(deserializer,"A", FIELDS, __Visitor)
fn deserialize_struct<V>(self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V)
-> Result<V::Value, Self::Error>
- where V: de::Visitor
+ where V: de::Visitor,
{
visitor.visit_map(self)
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
- where V: de::Visitor
+ where V: de::Visitor,
{
visitor.visit_seq(MapDeserializer::new(self.iter))
}
@@ -526,7 +509,6 @@ impl de::Deserializer for Deserializer {
use serde::de::value::{SeqDeserializer, ValueDeserializer};
-
impl de::MapVisitor for Deserializer {
type Error = Error;
@@ -537,10 +519,10 @@ impl de::MapVisitor for Deserializer {
if let Some((key, value)) = self.iter.next() {
self.value = Some(value);
- return seed.deserialize(key.into_deserializer()).map(Some)
+ return seed.deserialize(key.into_deserializer()).map(Some);
};
Ok(None)
-
+
}
fn visit_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
@@ -549,7 +531,8 @@ impl de::MapVisitor for Deserializer {
if let Some(v) = self.value.take() {
seed.deserialize(v.into_deserializer())
} else {
- Err(de::Error::custom("Somehow the list was empty after a non-empty key was returned"))
+ Err(de::Error::custom("Somehow the list was empty after a \
+ non-empty key was returned"))
}
}
}
@@ -575,50 +558,54 @@ impl de::Deserializer for LevelDeserializer {
if let Level::Nested(x) = self.0 {
Deserializer::with_map(x).deserialize_map(visitor)
} else {
- // Deserializer::with_map(BTreeMap::default()).deserialize_map(visitor)
- Err(de::Error::custom(format!("value: {:?} does not appear to be a map", self.0)))
+ Err(de::Error::custom(format!("value: {:?} does not appear to \
+ be a map",
+ self.0)))
}
}
- // _serde::Deserializer::deserialize_struct(deserializer,"A", FIELDS, __Visitor)
fn deserialize_struct<V>(self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V)
-> Result<V::Value, Self::Error>
- where V: de::Visitor
+ where V: de::Visitor,
{
self.deserialize_map(visitor)
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
- where V: de::Visitor
+ where V: de::Visitor,
{
match self.0 {
Level::Nested(map) => {
- SeqDeserializer::new(map.into_iter().map(|(_k, v)| v)).deserialize(visitor)
+ SeqDeserializer::new(map.into_iter().map(|(_k, v)| v))
+ .deserialize(visitor)
},
Level::Sequence(x) => {
SeqDeserializer::new(x.into_iter()).deserialize(visitor)
},
Level::Flat(x) => {
- SeqDeserializer::new(vec!(x).into_iter()).deserialize(visitor)
- }
+ SeqDeserializer::new(vec![x].into_iter()).deserialize(visitor)
+ },
_ => {
Err(de::Error::custom("value does not appear to be a sequence"))
- }
+ },
}
}
- fn deserialize_seq_fixed_size<V>(self, _len: usize, visitor: V)
- -> Result<V::Value, Self::Error> where V: de::Visitor
+ fn deserialize_seq_fixed_size<V>(self,
+ _len: usize,
+ visitor: V)
+ -> Result<V::Value, Self::Error>
+ where V: de::Visitor,
{
self.deserialize_seq(visitor)
}
- fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error> where V: de::Visitor
-
+ fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
+ where V: de::Visitor,
{
match self.0 {
Level::Flat(x) => {
@@ -627,10 +614,8 @@ impl de::Deserializer for LevelDeserializer {
} else {
visitor.visit_some(x.into_deserializer())
}
- }
- _ => {
- Err(de::Error::custom("value does not appear to be a value"))
- }
+ },
+ _ => Err(de::Error::custom("value does not appear to be a value")),
}
}
@@ -664,8 +649,7 @@ impl de::Deserializer for LevelDeserializer {
}
}
-impl ValueDeserializer for Level
-{
+impl ValueDeserializer for Level {
type Deserializer = LevelDeserializer;
fn into_deserializer(self) -> Self::Deserializer {
LevelDeserializer(self)
diff --git a/src/lib.rs b/src/lib.rs
index f28d916..b647eb5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,16 +4,59 @@
//! _nested_ urlencoded queries.
//!
//! This library aims for compatability with the syntax of
-//! [qs](https://github.com/ljharb/qs) and also of the [Rack::Utils::parse_neste
-//! d_query](http://www.rubydoc.info/github/rack/rack/Rack/Utils
-//! #parse_nested_query-class_method) implementation.
+//! [qs](https://github.com/ljharb/qs) and also of the
+//! [Rack::Utils::parse_nested_query](http://www.rubydoc.info/github/rack/rack/Rack/Utils#parse_nested_query-class_method)
+//! implementation.
//!
//! For users who do *not* require nested URL parameters, it is highly
-//! recommended that the `serde_urlencoded` crate is used instead, which
+//! recommended that the `serde_urlencoded` crate is used instead, which
//! will almost certainly perform better for deserializing simple inputs.
-//!
+//!
//! The serialization implementation of this library is adapted from
//! `serde_urlencoded`.
+//!
+//! ## Usage
+//!
+//! See the examples folder for a more detailed introduction.
+//!
+//! Serializing/Deserializing is designed to work with maps and structs.
+//!
+//! ```
+//!
+//!
+//! #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+//! struct Address {
+//! city: String,
+//! postcode: String,
+//! }
+//! #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+//! struct QueryParams {
+//! id: u8,
+//! name: String,
+//! address: Address,
+//! phone: u32,
+//! user_ids: Vec<u8>,
+//! }
+//!
+//! # fn main() {
+//! let params = QueryParams {
+//! id: 42,
+//! name: "Acme".to_string(),
+//! phone: 12345,
+//! address: Address {
+//! city: "Carrot City".to_string(),
+//! postcode: "12345".to_string(),
+//! },
+//! user_ids: vec![1, 2, 3, 4],
+//! };
+//! let rec_params: QueryParams = qs::from_str("\
+//! name=Acme&id=42&phone=12345&address[postcode]=12345&\
+//! address[city]=Carrot+City&user_ids[0]=1&user_ids[1]=2&\
+//! user_ids[2]=3&user_ids[3]=4")
+//! .unwrap();
+//! assert_eq!(rec_params, params);
+//!
+//! # }
extern crate itoa;
extern crate dtoa;
diff --git a/src/ser/key.rs b/src/ser/key.rs
index 5b2ccdd..10f1fff 100644
--- a/src/ser/key.rs
+++ b/src/ser/key.rs
@@ -1,7 +1,7 @@
-use ser::{Error};
-use serde::ser::{SerializeSeq, SerializeStruct};
+use ser::Error;
use ser::part::Sink;
use serde::Serialize;
+use serde::ser::{SerializeSeq, SerializeStruct};
use std::borrow::Cow;
use std::ops::Deref;
@@ -35,7 +35,7 @@ pub struct KeySink<End> {
}
impl<End, Ok> KeySink<End>
- where End: for<'key> FnOnce(Key<'key>) -> Result<Ok, Error>
+ where End: for<'key> FnOnce(Key<'key>) -> Result<Ok, Error>,
{
pub fn new(end: End) -> Self {
KeySink { end: end }
@@ -43,12 +43,9 @@ impl<End, Ok> KeySink<End>
}
impl<End, Ok> Sink<Ok, Error> for KeySink<End>
- where End: for<'key> FnOnce(Key<'key>) -> Result<Ok, Error>
+ where End: for<'key> FnOnce(Key<'key>) -> Result<Ok, Error>,
{
-
- fn serialize_static_str(self,
- value: &'static str)
- -> Result<Ok, Error> {
+ fn serialize_static_str(self, value: &'static str) -> Result<Ok, Error> {
(self.end)(Key::Static(value))
}
@@ -76,15 +73,15 @@ impl<End, Ok> Sink<Ok, Error> for KeySink<End>
}
impl<End, Ok> SerializeStruct for KeySink<End>
-where End: for<'key> FnOnce(Key<'key>) -> Result<Ok, Error>
+ where End: for<'key> FnOnce(Key<'key>) -> Result<Ok, Error>,
{
type Ok = Ok;
type Error = Error;
fn serialize_field<T: ?Sized + Serialize>(&mut self,
- _key: &'static str,
- _value: &T)
- -> Result<(), Error> {
+ _key: &'static str,
+ _value: &T)
+ -> Result<(), Error> {
Err(self.unsupported())
}
@@ -94,14 +91,14 @@ where End: for<'key> FnOnce(Key<'key>) -> Result<Ok, Error>
}
impl<End, Ok> SerializeSeq for KeySink<End>
-where End: for<'key> FnOnce(Key<'key>) -> Result<Ok, Error>
+ where End: for<'key> FnOnce(Key<'key>) -> Result<Ok, Error>,
{
type Ok = Ok;
type Error = Error;
fn serialize_element<T: ?Sized + Serialize>(&mut self,
- _value: &T)
- -> Result<(), Error> {
+ _value: &T)
+ -> Result<(), Error> {
Err(self.unsupported())
}
@@ -109,6 +106,3 @@ where End: for<'key> FnOnce(Key<'key>) -> Result<Ok, Error>
Err(self.unsupported())
}
}
-
-
-
diff --git a/src/ser/mod.rs b/src/ser/mod.rs
index f732bb3..67ed046 100644
--- a/src/ser/mod.rs
+++ b/src/ser/mod.rs
@@ -22,14 +22,14 @@ use url::form_urlencoded::Target as UrlEncodedTarget;
/// struct Query {
/// name: String,
/// age: u8,
-/// occupation: String,
+/// occupation: String,
/// }
///
/// # fn main(){
/// let q = Query {
/// name: "Alice".to_owned(),
/// age: 24,
-/// occupation: "Student".to_owned(),
+/// occupation: "Student".to_owned(),
/// };
///
///
@@ -389,7 +389,8 @@ impl<'output, Target> ser::SerializeTuple for TupleSerializer<'output, Target>
}
impl<'output, Target> ser::SerializeTupleStruct
- for TupleStructSerializer<'output, Target>
+ for
+ TupleStructSerializer<'output, Target>
where Target: 'output + UrlEncodedTarget,
{
type Ok = &'output mut UrlEncodedSerializer<Target>;
@@ -407,7 +408,8 @@ impl<'output, Target> ser::SerializeTupleStruct
}
impl<'output, Target> ser::SerializeTupleVariant
- for TupleVariantSerializer<'output, Target>
+ for
+ TupleVariantSerializer<'output, Target>
where Target: 'output + UrlEncodedTarget,
{
type Ok = &'output mut UrlEncodedSerializer<Target>;
@@ -491,7 +493,8 @@ impl<'output, Target> ser::SerializeStruct for StructSerializer<'output, Target>
}
impl<'output, Target> ser::SerializeStructVariant
- for StructVariantSerializer<'output, Target>
+ for
+ StructVariantSerializer<'output, Target>
where Target: 'output + UrlEncodedTarget,
{
type Ok = &'output mut UrlEncodedSerializer<Target>;
diff --git a/src/ser/part.rs b/src/ser/part.rs
index 4cf90b3..949af61 100644
--- a/src/ser/part.rs
+++ b/src/ser/part.rs
@@ -1,10 +1,10 @@
use dtoa;
use itoa;
use ser::Error;
-use serde::ser;
use serde;
-use std::str;
+use serde::ser;
use std::marker::PhantomData;
+use std::str;
pub struct PartSerializer<SO, S: Sink<SO, Error>> {
sink: S,
@@ -13,15 +13,19 @@ pub struct PartSerializer<SO, S: Sink<SO, Error>> {
impl<SO, S: Sink<SO, Error>> PartSerializer<SO, S> {
pub fn new(sink: S) -> Self {
- PartSerializer { sink: sink, marker: PhantomData }
+ PartSerializer {
+ sink: sink,
+ marker: PhantomData,
+ }
}
}
-pub trait Sink<S, E>: Sized + ser::SerializeStruct<Ok=S, Error=E> + ser::SerializeSeq<Ok=S, Error=E>
+pub trait Sink<S, E>: Sized + ser::SerializeStruct<Ok=S, Error=E>
+ + ser::SerializeSeq<Ok=S, Error=E>
where E: serde::ser::Error
{
- // type Ok;
- // type Error;
+// type Ok;
+// type Error;
fn serialize_static_str(self,
value: &'static str)
-> Result<S, Error>;
diff --git a/src/ser/value.rs b/src/ser/value.rs
index 5ed80b9..f2fc617 100644
--- a/src/ser/value.rs
+++ b/src/ser/value.rs
@@ -68,9 +68,9 @@ impl<'key, 'target, Target> SerializeStruct for ValueSink<'key, 'target, Target>
type Error = Error;
fn serialize_field<T: ?Sized + Serialize>(&mut self,
- key: &'static str,
- value: &T)
- -> Result<(), Error> {
+ key: &'static str,
+ value: &T)
+ -> Result<(), Error> {
let newk = format!("{}[{}]", self.key, key);
let value_sink = ValueSink::new(self.urlencoder, &newk);
value.serialize(super::part::PartSerializer::new(value_sink))
@@ -88,8 +88,8 @@ impl<'key, 'target, Target> SerializeSeq for ValueSink<'key, 'target, Target>
type Error = Error;
fn serialize_element<T: ?Sized + Serialize>(&mut self,
- value: &T)
- -> Result<(), Error> {
+ value: &T)
+ -> Result<(), Error> {
let newk = format!("{}[{}]", self.key, self.idx);
self.idx += 1;
let value_sink = ValueSink::new(self.urlencoder, &newk);
@@ -100,4 +100,3 @@ impl<'key, 'target, Target> SerializeSeq for ValueSink<'key, 'target, Target>
Ok(())
}
}
-
diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs
index 1e83589..0bc60ab 100644
--- a/tests/test_deserialize.rs
+++ b/tests/test_deserialize.rs
@@ -19,6 +19,8 @@ struct QueryParams {
user_ids: Vec<u8>,
}
+// Compares a map generated by hash_to_map with the map returned by
+// qs::from_str. All types are inferred by the compiler.
macro_rules! map_test {
($string:expr, $($mapvars:tt)*) => {
let expected_map = hash_to_map!(New $($mapvars)*);
@@ -28,10 +30,11 @@ macro_rules! map_test {
}
+// Macro used to quickly generate a nested HashMap from a string.
macro_rules! hash_to_map {
- // Base case: a map with no inputs, do nothing
+ // Base case: a map with no inputs, do nothing.
($map:expr, ) => ();
- //{}
+ //{}
// This parses a single map entry, with a value explicitly an expression.
($map:expr, $k:tt[e $v:expr] $($rest:tt)*) => {{
$map.insert($k.to_owned(), $v.to_owned());
@@ -44,8 +47,8 @@ macro_rules! hash_to_map {
hash_to_map!($map, $($rest)*);
}};
- // This parses the first entry as a nested entry, and tail calls the remaining
- // in rest.
+ // This parses the first entry as a nested entry, and tail calls the
+ // remaining in rest.
($map:expr, $k:tt[$($inner:tt)*] $($rest:tt)*) => {{
let mut inner_map = HashMap::new();
hash_to_map!(inner_map, $($inner)*);
@@ -60,7 +63,7 @@ macro_rules! hash_to_map {
hash_to_map!(map, $($rest)*);
map
}}
-
+
}
#[test]
@@ -73,19 +76,38 @@ fn deserialize_struct() {
city: "Carrot City".to_string(),
postcode: "12345".to_string(),
},
- user_ids: vec!(1,2,3,4),
+ user_ids: vec![1, 2, 3, 4],
};
- let rec_params: QueryParams = qs::from_str("name=Acme&id=42&phone=12345&address[postcode]=12345&address[city]=Carrot+City&user_ids[0]=1&user_ids[1]=2&user_ids[2]=3&user_ids[3]=4").unwrap();
+ // standard parameters
+ let rec_params: QueryParams = qs::from_str("\
+ name=Acme&id=42&phone=12345&address[postcode]=12345&\
+ address[city]=Carrot+City&user_ids[0]=1&user_ids[1]=2&\
+ user_ids[2]=3&user_ids[3]=4")
+ .unwrap();
assert_eq!(rec_params, params);
- let rec_params: QueryParams = qs::from_str("name=Acme&id=42&phone=12345&address[postcode]=12345&address[city]=Carrot+City&user_ids[]=1&user_ids[]=2&user_ids[]=3&user_ids[]=4").unwrap();
+
+ // unindexed arrays
+ let rec_params: QueryParams = qs::from_str("\
+ name=Acme&id=42&phone=12345&address[postcode]=12345&\
+ address[city]=Carrot+City&user_ids[]=1&user_ids[]=2&\
+ user_ids[]=3&user_ids[]=4")
+ .unwrap();
+ assert_eq!(rec_params, params);
+
+ // ordering doesn't matter
+ let rec_params: QueryParams = qs::from_str("\
+ address[city]=Carrot+City&user_ids[]=1&user_ids[]=2&\
+ name=Acme&id=42&phone=12345&address[postcode]=12345&\
+ user_ids[]=3&user_ids[]=4")
+ .unwrap();
assert_eq!(rec_params, params);
}
#[test]
fn qs_test_simple() {
-// test('parse()', function (t) {
+ // test('parse()', function (t) {
// t.test('parses a simple string', function (st) {
// st.deepEqual(qs.parse('0=foo'), { 0: 'foo' });
map_test!("0=foo", 0["foo"]);
@@ -102,7 +124,8 @@ fn qs_test_simple() {
// st.deepEqual(qs.parse('a[==]=23'), { a: { '==': '23' } });
map_test!("a[==]=23", "a"["=="[23]]);
- // st.deepEqual(qs.parse('foo', { strictNullHandling: true }), { foo: null });
+ // st.deepEqual(qs.parse('foo', { strictNullHandling: true }),
+ // { foo: null });
let none: Option<String> = Option::None;
map_test!("foo", "foo"[none]);
@@ -127,13 +150,15 @@ fn qs_test_simple() {
// st.deepEqual(qs.parse('foo2=bar2&baz2='), { foo2: 'bar2', baz2: '' });
map_test!("foo2=bar2&baz2=", "foo2"["bar2"] "baz2"[""]);
- // st.deepEqual(qs.parse('foo=bar&baz', { strictNullHandling: true }), { foo: 'bar', baz: null });
+ // st.deepEqual(qs.parse('foo=bar&baz', { strictNullHandling: true }), {
+ // foo: 'bar', baz: null });
map_test!("foo=bar&baz", "foo"[e Some("bar".to_string())] "baz"[e None]);
// st.deepEqual(qs.parse('foo=bar&baz'), { foo: 'bar', baz: '' });
map_test!("foo=bar&baz", "foo"["bar"] "baz"[""]);
- // st.deepEqual(qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World'), {
+ // st.deepEqual(qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World'),
+ // {
// cht: 'p3',
// chd: 't:60,40',
// chs: '250x100',
@@ -146,20 +171,23 @@ fn qs_test_simple() {
"chl"["Hello|World"]
);
// st.end();
-// });
+ // });
}
#[test]
fn qs_nesting() {
- // t.deepEqual(qs.parse('a[b]=c'), { a: { b: 'c' } }, 'parses a single nested string');
- // map_test!("a[b]=c", "a"["b"["c"]]);
+ // t.deepEqual(qs.parse('a[b]=c'), { a: { b: 'c' } }, 'parses a single
+ // nested string');
+ map_test!("a[b]=c", "a"["b"["c"]]);
- // t.deepEqual(qs.parse('a[b][c]=d'), { a: { b: { c: 'd' } } }, 'parses a double nested string');
+ // t.deepEqual(qs.parse('a[b][c]=d'), { a: { b: { c: 'd' } } }, 'parses a
+ // double nested string');
map_test!("a[b][c]=d", "a"["b"["c"["d"]]]);
// t.deepEqual(
// qs.parse('a[b][c][d][e][f][g][h]=i'),
// { a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } },
// 'defaults to a depth of 5'
// );
- // map_test!("a[b][c][d][e][f][g][h]=i", "a"["b"["c"["d"["e"["f"["[g][h]"["i"]]]]]]]);
+ map_test!("a[b][c][d][e][f][g][h]=i",
+ "a"["b"["c"["d"["e"["f"["[g][h]"["i"]]]]]]]);
}
diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs
index af66903..4a9964a 100644
--- a/tests/test_serialize.rs
+++ b/tests/test_serialize.rs
@@ -28,10 +28,14 @@ fn serialize_struct() {
city: "Carrot City".to_string(),
postcode: "12345".to_string(),
},
- user_ids: vec!(1,2,3,4),
+ user_ids: vec![1, 2, 3, 4],
};
- assert_eq!(qs::to_string(&params).unwrap(), urlencode("id=42&name=Acme&phone=12345&address[city]=Carrot+City&address[postcode]=12345&user_ids[0]=1&user_ids[1]=2&user_ids[2]=3&user_ids[3]=4"));
+ assert_eq!(qs::to_string(&params).unwrap(),
+ urlencode("\
+ id=42&name=Acme&phone=12345&address[city]=Carrot+City&\
+ address[postcode]=12345&user_ids[0]=1&user_ids[1]=2&\
+ user_ids[2]=3&user_ids[3]=4"));
}
fn urlencode(input: &str) -> String {