Merge pull request #1256 from serde-rs/option
Support flattened untagged Options in struct fields
This commit is contained in:
commit
2ee347c5a5
@ -529,6 +529,14 @@ where
|
|||||||
{
|
{
|
||||||
T::deserialize(deserializer).map(Some)
|
T::deserialize(deserializer).map(Some)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn __private_visit_untagged_option<D>(self, deserializer: D) -> Result<Self::Value, ()>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
Ok(T::deserialize(deserializer).ok())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de, T> Deserialize<'de> for Option<T>
|
impl<'de, T> Deserialize<'de> for Option<T>
|
||||||
|
@ -1529,6 +1529,15 @@ pub trait Visitor<'de>: Sized {
|
|||||||
let _ = data;
|
let _ = data;
|
||||||
Err(Error::invalid_type(Unexpected::Enum, &self))
|
Err(Error::invalid_type(Unexpected::Enum, &self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used when deserializing a flattened Option field. Not public API.
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn __private_visit_untagged_option<D>(self, _: D) -> Result<Self::Value, ()>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -2645,10 +2645,7 @@ impl<'a, 'de, E> FlatMapDeserializer<'a, 'de, E>
|
|||||||
where
|
where
|
||||||
E: Error,
|
E: Error,
|
||||||
{
|
{
|
||||||
fn deserialize_other<V>(self, _: V) -> Result<V::Value, E>
|
fn deserialize_other<V>() -> Result<V, E> {
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
Err(Error::custom("can only flatten structs and maps"))
|
Err(Error::custom("can only flatten structs and maps"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2657,11 +2654,11 @@ where
|
|||||||
macro_rules! forward_to_deserialize_other {
|
macro_rules! forward_to_deserialize_other {
|
||||||
($($func:ident ( $($arg:ty),* ))*) => {
|
($($func:ident ( $($arg:ty),* ))*) => {
|
||||||
$(
|
$(
|
||||||
fn $func<V>(self, $(_: $arg,)* visitor: V) -> Result<V::Value, Self::Error>
|
fn $func<V>(self, $(_: $arg,)* _visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
self.deserialize_other(visitor)
|
Self::deserialize_other()
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
@ -2741,6 +2738,16 @@ where
|
|||||||
visitor.visit_newtype_struct(self)
|
visitor.visit_newtype_struct(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
match visitor.__private_visit_untagged_option(self) {
|
||||||
|
Ok(value) => Ok(value),
|
||||||
|
Err(()) => Self::deserialize_other(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
forward_to_deserialize_other! {
|
forward_to_deserialize_other! {
|
||||||
deserialize_bool()
|
deserialize_bool()
|
||||||
deserialize_i8()
|
deserialize_i8()
|
||||||
@ -2758,7 +2765,6 @@ where
|
|||||||
deserialize_string()
|
deserialize_string()
|
||||||
deserialize_bytes()
|
deserialize_bytes()
|
||||||
deserialize_byte_buf()
|
deserialize_byte_buf()
|
||||||
deserialize_option()
|
|
||||||
deserialize_unit()
|
deserialize_unit()
|
||||||
deserialize_unit_struct(&'static str)
|
deserialize_unit_struct(&'static str)
|
||||||
deserialize_seq()
|
deserialize_seq()
|
||||||
|
@ -1122,14 +1122,14 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(self.bad_type(Unsupported::Optional))
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_some<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
|
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
{
|
{
|
||||||
Err(self.bad_type(Unsupported::Optional))
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||||
|
@ -2095,3 +2095,84 @@ fn test_flatten_untagged_enum() {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_flatten_option() {
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct Outer {
|
||||||
|
#[serde(flatten)]
|
||||||
|
inner1: Option<Inner1>,
|
||||||
|
#[serde(flatten)]
|
||||||
|
inner2: Option<Inner2>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct Inner1 {
|
||||||
|
inner1: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct Inner2 {
|
||||||
|
inner2: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Outer {
|
||||||
|
inner1: Some(Inner1 {
|
||||||
|
inner1: 1,
|
||||||
|
}),
|
||||||
|
inner2: Some(Inner2 {
|
||||||
|
inner2: 2,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("inner1"),
|
||||||
|
Token::I32(1),
|
||||||
|
Token::Str("inner2"),
|
||||||
|
Token::I32(2),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Outer {
|
||||||
|
inner1: Some(Inner1 {
|
||||||
|
inner1: 1,
|
||||||
|
}),
|
||||||
|
inner2: None,
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("inner1"),
|
||||||
|
Token::I32(1),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Outer {
|
||||||
|
inner1: None,
|
||||||
|
inner2: Some(Inner2 {
|
||||||
|
inner2: 2,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("inner2"),
|
||||||
|
Token::I32(2),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Outer {
|
||||||
|
inner1: None,
|
||||||
|
inner2: None,
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user