urlencoded: (de)serialize nested structs as JSON
This commit is contained in:
parent
053d2e94f6
commit
7972453e91
@ -233,8 +233,12 @@ impl<'de> de::Deserializer<'de> for Part<'de> {
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
if self.0 == "null" {
|
||||
visitor.visit_none()
|
||||
} else {
|
||||
visitor.visit_some(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
@ -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! {
|
||||
char
|
||||
str
|
||||
@ -278,7 +305,6 @@ impl<'de> de::Deserializer<'de> for Part<'de> {
|
||||
byte_buf
|
||||
unit_struct
|
||||
tuple_struct
|
||||
struct
|
||||
identifier
|
||||
tuple
|
||||
ignored_any
|
||||
|
@ -32,6 +32,8 @@ pub struct PairSerializer<'input, 'target, Target: 'target + UrlEncodedTarget> {
|
||||
state: PairState,
|
||||
key: Option<&'target Cow<'target, str>>,
|
||||
count: &'target mut usize,
|
||||
len: usize,
|
||||
json_buf: String,
|
||||
}
|
||||
|
||||
impl<'input, 'target, Target> PairSerializer<'input, 'target, Target>
|
||||
@ -48,6 +50,8 @@ where
|
||||
state: PairState::WaitingForKey,
|
||||
key,
|
||||
count,
|
||||
len: 0,
|
||||
json_buf: String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -64,7 +68,7 @@ where
|
||||
type SerializeTupleStruct = ser::Impossible<(), Error>;
|
||||
type SerializeTupleVariant = ser::Impossible<(), Error>;
|
||||
type SerializeMap = ser::Impossible<(), Error>;
|
||||
type SerializeStruct = ser::Impossible<(), Error>;
|
||||
type SerializeStruct = Self;
|
||||
type SerializeStructVariant = ser::Impossible<(), Error>;
|
||||
|
||||
serialize_pair! {
|
||||
@ -177,11 +181,12 @@ where
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
mut self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeStruct> {
|
||||
Err(Error::unsupported_pair())
|
||||
self.len = len;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
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
|
||||
for PairSerializer<'input, 'target, Target>
|
||||
where
|
||||
|
@ -1,5 +1,6 @@
|
||||
use ruma_serde::urlencoded;
|
||||
use serde::Deserialize;
|
||||
use url::form_urlencoded::Serializer as Encoder;
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq)]
|
||||
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));
|
||||
}
|
||||
|
||||
#[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 serde::Serialize;
|
||||
use url::form_urlencoded::Serializer as Encoder;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct NewType<T>(T);
|
||||
@ -190,3 +191,71 @@ fn serialize_map() {
|
||||
let encoded = urlencoded::to_string(s).unwrap();
|
||||
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