urlencoded: (de)serialize nested structs as JSON
This commit is contained in:
parent
053d2e94f6
commit
7972453e91
@ -233,7 +233,11 @@ impl<'de> de::Deserializer<'de> for Part<'de> {
|
|||||||
where
|
where
|
||||||
V: de::Visitor<'de>,
|
V: de::Visitor<'de>,
|
||||||
{
|
{
|
||||||
visitor.visit_some(self)
|
if self.0 == "null" {
|
||||||
|
visitor.visit_none()
|
||||||
|
} else {
|
||||||
|
visitor.visit_some(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_enum<V>(
|
fn deserialize_enum<V>(
|
||||||
@ -269,6 +273,29 @@ impl<'de> de::Deserializer<'de> for Part<'de> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_struct<V>(
|
||||||
|
self,
|
||||||
|
name: &'static str,
|
||||||
|
fields: &'static [&'static str],
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: de::Visitor<'de>,
|
||||||
|
{
|
||||||
|
let pairs = self
|
||||||
|
.1
|
||||||
|
.ok_or_else(|| Error::custom("percent decoding may have failed"))?;
|
||||||
|
|
||||||
|
let raw_json = pairs
|
||||||
|
.get(0)
|
||||||
|
.ok_or_else(|| Error::custom("no value found for nested struct"))?;
|
||||||
|
|
||||||
|
let mut de =
|
||||||
|
serde_json::de::Deserializer::from_reader(raw_json.as_bytes());
|
||||||
|
de.deserialize_struct(name, fields, visitor)
|
||||||
|
.map_err(|e| Error::custom(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
serde::forward_to_deserialize_any! {
|
serde::forward_to_deserialize_any! {
|
||||||
char
|
char
|
||||||
str
|
str
|
||||||
@ -278,7 +305,6 @@ impl<'de> de::Deserializer<'de> for Part<'de> {
|
|||||||
byte_buf
|
byte_buf
|
||||||
unit_struct
|
unit_struct
|
||||||
tuple_struct
|
tuple_struct
|
||||||
struct
|
|
||||||
identifier
|
identifier
|
||||||
tuple
|
tuple
|
||||||
ignored_any
|
ignored_any
|
||||||
|
@ -32,6 +32,8 @@ pub struct PairSerializer<'input, 'target, Target: 'target + UrlEncodedTarget> {
|
|||||||
state: PairState,
|
state: PairState,
|
||||||
key: Option<&'target Cow<'target, str>>,
|
key: Option<&'target Cow<'target, str>>,
|
||||||
count: &'target mut usize,
|
count: &'target mut usize,
|
||||||
|
len: usize,
|
||||||
|
json_buf: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'input, 'target, Target> PairSerializer<'input, 'target, Target>
|
impl<'input, 'target, Target> PairSerializer<'input, 'target, Target>
|
||||||
@ -48,6 +50,8 @@ where
|
|||||||
state: PairState::WaitingForKey,
|
state: PairState::WaitingForKey,
|
||||||
key,
|
key,
|
||||||
count,
|
count,
|
||||||
|
len: 0,
|
||||||
|
json_buf: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,7 +68,7 @@ where
|
|||||||
type SerializeTupleStruct = ser::Impossible<(), Error>;
|
type SerializeTupleStruct = ser::Impossible<(), Error>;
|
||||||
type SerializeTupleVariant = ser::Impossible<(), Error>;
|
type SerializeTupleVariant = ser::Impossible<(), Error>;
|
||||||
type SerializeMap = ser::Impossible<(), Error>;
|
type SerializeMap = ser::Impossible<(), Error>;
|
||||||
type SerializeStruct = ser::Impossible<(), Error>;
|
type SerializeStruct = Self;
|
||||||
type SerializeStructVariant = ser::Impossible<(), Error>;
|
type SerializeStructVariant = ser::Impossible<(), Error>;
|
||||||
|
|
||||||
serialize_pair! {
|
serialize_pair! {
|
||||||
@ -177,11 +181,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_struct(
|
fn serialize_struct(
|
||||||
self,
|
mut self,
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
_len: usize,
|
len: usize,
|
||||||
) -> Result<Self::SerializeStruct> {
|
) -> Result<Self::SerializeStruct> {
|
||||||
Err(Error::unsupported_pair())
|
self.len = len;
|
||||||
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_struct_variant(
|
fn serialize_struct_variant(
|
||||||
@ -195,6 +200,51 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'input, 'target, Target> ser::SerializeStruct
|
||||||
|
for PairSerializer<'input, 'target, Target>
|
||||||
|
where
|
||||||
|
Target: 'target + UrlEncodedTarget,
|
||||||
|
{
|
||||||
|
type Ok = ();
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize_field<T: ?Sized>(
|
||||||
|
&mut self,
|
||||||
|
key: &'static str,
|
||||||
|
value: &T,
|
||||||
|
) -> Result<()>
|
||||||
|
where
|
||||||
|
T: ser::Serialize,
|
||||||
|
{
|
||||||
|
*self.count += 1;
|
||||||
|
if self.json_buf.is_empty() {
|
||||||
|
self.json_buf.push_str("{");
|
||||||
|
}
|
||||||
|
let json_blob = serde_json::to_string(value)
|
||||||
|
.map_err(|e| Error::Custom(e.to_string().into()))?;
|
||||||
|
|
||||||
|
if *self.count == self.len {
|
||||||
|
self.json_buf
|
||||||
|
.push_str(&format!("\"{}\":{}", key, json_blob));
|
||||||
|
} else {
|
||||||
|
self.json_buf
|
||||||
|
.push_str(&format!("\"{}\":{},", key, json_blob));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(mut self) -> Result<Self::Ok> {
|
||||||
|
use serde::ser::Serialize;
|
||||||
|
|
||||||
|
self.json_buf.push_str("}");
|
||||||
|
self.json_buf.serialize(PairSerializer::new(
|
||||||
|
self.urlencoder,
|
||||||
|
self.key,
|
||||||
|
&mut self.count,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'input, 'target, Target> ser::SerializeSeq
|
impl<'input, 'target, Target> ser::SerializeSeq
|
||||||
for PairSerializer<'input, 'target, Target>
|
for PairSerializer<'input, 'target, Target>
|
||||||
where
|
where
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use ruma_serde::urlencoded;
|
use ruma_serde::urlencoded;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use url::form_urlencoded::Serializer as Encoder;
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, PartialEq)]
|
#[derive(Deserialize, Debug, PartialEq)]
|
||||||
struct NewType<T>(T);
|
struct NewType<T>(T);
|
||||||
@ -183,3 +184,81 @@ fn deserialize_struct_unit_enum() {
|
|||||||
|
|
||||||
assert_eq!(urlencoded::from_str("item=A&item=B&item=C"), Ok(result));
|
assert_eq!(urlencoded::from_str("item=A&item=B&item=C"), Ok(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
|
struct Nested<T> {
|
||||||
|
item: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
|
struct Inner {
|
||||||
|
c: String,
|
||||||
|
a: usize,
|
||||||
|
b: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
|
struct InnerList<T> {
|
||||||
|
list: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_nested() {
|
||||||
|
let mut encoder = Encoder::new(String::new());
|
||||||
|
|
||||||
|
let nested = Nested {
|
||||||
|
item: Inner {
|
||||||
|
c: "hello".into(),
|
||||||
|
a: 10,
|
||||||
|
b: "bye".into(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
nested,
|
||||||
|
urlencoded::from_str::<Nested<Inner>>(
|
||||||
|
&encoder
|
||||||
|
.append_pair("item", r#"{"c":"hello","a":10,"b":"bye"}"#)
|
||||||
|
.finish(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_nested_list() {
|
||||||
|
let mut encoder = Encoder::new(String::new());
|
||||||
|
|
||||||
|
let nested = Nested {
|
||||||
|
item: InnerList {
|
||||||
|
list: vec![1, 2, 3],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
nested,
|
||||||
|
urlencoded::from_str::<Nested<InnerList<u8>>>(
|
||||||
|
&encoder.append_pair("item", r#"{"list":[1,2,3]}"#).finish(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_nested_list_option() {
|
||||||
|
let mut encoder = Encoder::new(String::new());
|
||||||
|
|
||||||
|
let nested = Nested {
|
||||||
|
item: InnerList {
|
||||||
|
list: vec![Some(1), Some(2), None],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
nested,
|
||||||
|
urlencoded::from_str::<Nested<InnerList<Option<u8>>>>(
|
||||||
|
&encoder
|
||||||
|
.append_pair("item", r#"{"list":[1,2,null]}"#)
|
||||||
|
.finish(),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use ruma_serde::urlencoded;
|
use ruma_serde::urlencoded;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use url::form_urlencoded::Serializer as Encoder;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct NewType<T>(T);
|
struct NewType<T>(T);
|
||||||
@ -190,3 +191,71 @@ fn serialize_map() {
|
|||||||
let encoded = urlencoded::to_string(s).unwrap();
|
let encoded = urlencoded::to_string(s).unwrap();
|
||||||
assert_eq!("hello=world&matrix=ruma&seri=alize", encoded);
|
assert_eq!("hello=world&matrix=ruma&seri=alize", encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Nested<T> {
|
||||||
|
item: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Inner {
|
||||||
|
c: String,
|
||||||
|
a: usize,
|
||||||
|
b: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, PartialEq)]
|
||||||
|
struct InnerList<T> {
|
||||||
|
list: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_nested() {
|
||||||
|
let mut encoder = Encoder::new(String::new());
|
||||||
|
|
||||||
|
let s = Nested {
|
||||||
|
item: Inner {
|
||||||
|
c: "hello".into(),
|
||||||
|
a: 10,
|
||||||
|
b: "bye".into(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
encoder
|
||||||
|
.append_pair("item", r#"{"c":"hello","a":10,"b":"bye"}"#)
|
||||||
|
.finish(),
|
||||||
|
urlencoded::to_string(s).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_nested_list() {
|
||||||
|
let mut encoder = Encoder::new(String::new());
|
||||||
|
|
||||||
|
let s = Nested {
|
||||||
|
item: InnerList {
|
||||||
|
list: vec![1, 2, 3],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
encoder.append_pair("item", r#"{"list":[1,2,3]}"#).finish(),
|
||||||
|
urlencoded::to_string(s).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_nested_list_option() {
|
||||||
|
let mut encoder = Encoder::new(String::new());
|
||||||
|
|
||||||
|
let s = Nested {
|
||||||
|
item: InnerList {
|
||||||
|
list: vec![Some(1), Some(2), None],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
encoder
|
||||||
|
.append_pair("item", r#"{"list":[1,2,null]}"#)
|
||||||
|
.finish(),
|
||||||
|
urlencoded::to_string(s).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user