summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Scott <sam.scott89@gmail.com>2019-01-23 11:13:18 -0500
committerSam Scott <sam.scott89@gmail.com>2019-01-23 11:13:18 -0500
commitb69c42eb9b9f055e74353c9c149074616eff181f (patch)
tree2cf99efcf18ae20feed9fd843771e96be0bd3b9d
parent6689581cfa2b9eacd6ec5d6402cb920fecf1eb63 (diff)
Add documentation and workaroud for `#[serde(flatten)]` usage.
-rw-r--r--src/lib.rs48
-rw-r--r--tests/test_deserialize.rs59
-rw-r--r--tests/test_serialize.rs21
3 files changed, 128 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 15e4036..1c3d33e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -97,7 +97,55 @@
//! using keys with square brackets in them, or unexpected things can
//! happen.
//!
+//! ## Flatten workaround
+//!
+//! A current [known limitation](https://github.com/serde-rs/serde/issues/1183)
+//! in `serde` is deserializing `#[serde(flatten)]` structs for formats which
+//! are not self-describing. This includes query strings: `12` can be an integer
+//! or a string, for example.
+//!
+//! We suggest the following workaround:
+//!
+//! ```
+//! extern crate serde;
+//! #[macro_use]
+//! extern crate serde_derive;
+//! extern crate serde_qs as qs;
+//!
+//! use serde::de::Error;
//!
+//! fn from_str<'de, D, S>(deserializer: D) -> Result<S, D::Error>
+//! where D: serde::Deserializer<'de>,
+//! S: std::str::FromStr
+//! {
+//! let s = <&str as serde::Deserialize>::deserialize(deserializer)?;
+//! S::from_str(&s).map_err(|_| D::Error::custom("could not parse string"))
+//! }
+//!
+//! #[derive(Deserialize, Serialize, Debug, PartialEq)]
+//! struct Query {
+//! a: u8,
+//! #[serde(flatten)]
+//! common: CommonParams,
+//! }
+//!
+//! #[derive(Deserialize, Serialize, Debug, PartialEq)]
+//! struct CommonParams {
+//! #[serde(deserialize_with="from_str")]
+//! limit: u64,
+//! #[serde(deserialize_with="from_str")]
+//! offset: u64,
+//! #[serde(deserialize_with="from_str")]
+//! remaining: bool,
+//! }
+//!
+//! fn main() {
+//! let params = "a=1&limit=100&offset=50&remaining=true";
+//! let query = Query { a: 1, common: CommonParams { limit: 100, offset: 50, remaining: true } };
+//! let rec_query: Result<Query, _> = qs::from_str(params);
+//! assert_eq!(rec_query.unwrap(), query);
+//! }
+//! ```
#![allow(
)]
diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs
index 946a8f3..81dc954 100644
--- a/tests/test_deserialize.rs
+++ b/tests/test_deserialize.rs
@@ -1,3 +1,4 @@
+extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_qs as qs;
@@ -479,3 +480,61 @@ fn strict_mode() {
fn square_brackets_in_values() {
map_test!("foo=%5BHello%5D", "foo"["[Hello]"]);
}
+
+#[test]
+#[ignore]
+fn deserialize_flatten() {
+ #[derive(Deserialize,Serialize,Debug, PartialEq)]
+ struct Query {
+ a: u8,
+ #[serde(flatten)]
+ common: CommonParams,
+ }
+
+ #[derive(Deserialize,Serialize,Debug, PartialEq)]
+ struct CommonParams {
+ limit: u64,
+ offset: u64,
+ remaining: bool,
+ }
+
+ let params = "a=1&limit=100&offset=50&remaining=true";
+ let query = Query { a: 1, common: CommonParams { limit: 100, offset: 50, remaining: true } };
+ let rec_query: Result<Query, _> = qs::from_str(params);
+ assert_eq!(rec_query.unwrap(), query);
+}
+
+#[test]
+fn deserialize_flatten_workaround() {
+ #[derive(Deserialize,Serialize,Debug, PartialEq)]
+ struct Query {
+ a: u8,
+ #[serde(flatten)]
+ common: CommonParams,
+ }
+
+ #[derive(Deserialize,Serialize,Debug, PartialEq)]
+ struct CommonParams {
+ #[serde(deserialize_with="from_str")]
+ limit: u64,
+ #[serde(deserialize_with="from_str")]
+ offset: u64,
+ #[serde(deserialize_with="from_str")]
+ remaining: bool,
+ }
+
+ let params = "a=1&limit=100&offset=50&remaining=true";
+ let query = Query { a: 1, common: CommonParams { limit: 100, offset: 50, remaining: true } };
+ let rec_query: Result<Query, _> = qs::from_str(params);
+ assert_eq!(rec_query.unwrap(), query);
+}
+
+use serde::de::Error;
+
+fn from_str<'de, D, S>(deserializer: D) -> Result<S, D::Error>
+ where D: serde::Deserializer<'de>,
+ S: std::str::FromStr
+{
+ let s = <&str as serde::Deserialize>::deserialize(deserializer)?;
+ S::from_str(&s).map_err(|_| D::Error::custom("could not parse string"))
+} \ No newline at end of file
diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs
index 80e2d7c..5a918ab 100644
--- a/tests/test_serialize.rs
+++ b/tests/test_serialize.rs
@@ -92,3 +92,24 @@ fn serialize_enum() {
let rec_params = qs::to_string(&query).unwrap();
assert_eq!(rec_params, params);
}
+
+#[test]
+fn serialize_flatten() {
+ #[derive(Deserialize,Serialize,Debug, PartialEq)]
+ struct Query {
+ a: u8,
+ #[serde(flatten)]
+ common: CommonParams,
+ }
+
+ #[derive(Deserialize,Serialize,Debug, PartialEq)]
+ struct CommonParams {
+ limit: u64,
+ offset: u64,
+ }
+
+ let params = "a=1&limit=100&offset=50";
+ let query = Query { a: 1, common: CommonParams { limit: 100, offset: 50 } };
+ let rec_params = qs::to_string(&query).unwrap();
+ assert_eq!(rec_params, params);
+}