Added support for struct variant enum serialization

This commit is contained in:
Armin Ronacher
2018-03-16 22:40:08 +01:00
parent d1833c5602
commit a8c8c2028e
2 changed files with 128 additions and 15 deletions
+61 -14
View File
@@ -11,7 +11,12 @@ use lib::*;
use ser::{self, Impossible, Serialize, SerializeMap, SerializeStruct, Serializer};
#[cfg(any(feature = "std", feature = "alloc"))]
use self::content::{SerializeStructVariantAsMapValue, SerializeTupleVariantAsMapValue};
use self::content::{
SerializeStructVariantAsMapValue,
SerializeTupleVariantAsMapValue,
ContentSerializer,
Content,
};
/// Used to check that serde(getter) attributes return the expected type.
/// Not public API.
@@ -461,7 +466,7 @@ mod content {
}
#[derive(Debug)]
enum Content {
pub enum Content {
Bool(bool),
U8(u8),
@@ -586,12 +591,12 @@ mod content {
}
}
struct ContentSerializer<E> {
pub struct ContentSerializer<E> {
error: PhantomData<E>,
}
impl<E> ContentSerializer<E> {
fn new() -> Self {
pub fn new() -> Self {
ContentSerializer { error: PhantomData }
}
}
@@ -806,7 +811,7 @@ mod content {
}
}
struct SerializeSeq<E> {
pub struct SerializeSeq<E> {
elements: Vec<Content>,
error: PhantomData<E>,
}
@@ -832,7 +837,7 @@ mod content {
}
}
struct SerializeTuple<E> {
pub struct SerializeTuple<E> {
elements: Vec<Content>,
error: PhantomData<E>,
}
@@ -858,7 +863,7 @@ mod content {
}
}
struct SerializeTupleStruct<E> {
pub struct SerializeTupleStruct<E> {
name: &'static str,
fields: Vec<Content>,
error: PhantomData<E>,
@@ -885,7 +890,7 @@ mod content {
}
}
struct SerializeTupleVariant<E> {
pub struct SerializeTupleVariant<E> {
name: &'static str,
variant_index: u32,
variant: &'static str,
@@ -919,7 +924,7 @@ mod content {
}
}
struct SerializeMap<E> {
pub struct SerializeMap<E> {
entries: Vec<(Content, Content)>,
key: Option<Content>,
error: PhantomData<E>,
@@ -969,7 +974,7 @@ mod content {
}
}
struct SerializeStruct<E> {
pub struct SerializeStruct<E> {
name: &'static str,
fields: Vec<(&'static str, Content)>,
error: PhantomData<E>,
@@ -996,7 +1001,7 @@ mod content {
}
}
struct SerializeStructVariant<E> {
pub struct SerializeStructVariant<E> {
name: &'static str,
variant_index: u32,
variant: &'static str,
@@ -1059,7 +1064,7 @@ impl<'a, M> Serializer for FlatMapSerializer<'a, M>
type SerializeMap = FlatMapSerializeMap<'a, M>;
type SerializeStruct = FlatMapSerializeStruct<'a, M>;
type SerializeTupleVariant = Impossible<Self::Ok, M::Error>;
type SerializeStructVariant = Impossible<Self::Ok, M::Error>;
type SerializeStructVariant = FlatMapSerializeStructVariantAsMapValue<'a, M>;
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::Boolean))
@@ -1212,10 +1217,11 @@ impl<'a, M> Serializer for FlatMapSerializer<'a, M>
self,
_: &'static str,
_: u32,
_: &'static str,
inner_variant: &'static str,
_: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
Err(self.bad_type(Unsupported::Enum))
try!(self.0.serialize_key(inner_variant));
Ok(FlatMapSerializeStructVariantAsMapValue::new(self.0, inner_variant))
}
}
@@ -1269,3 +1275,44 @@ impl<'a, M> ser::SerializeStruct for FlatMapSerializeStruct<'a, M>
Ok(())
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapSerializeStructVariantAsMapValue<'a, M: 'a> {
map: &'a mut M,
name: &'static str,
fields: Vec<(&'static str, Content)>,
}
impl<'a, M> FlatMapSerializeStructVariantAsMapValue<'a, M>
where M: SerializeMap + 'a
{
fn new(map: &'a mut M, name: &'static str) -> FlatMapSerializeStructVariantAsMapValue<'a, M> {
FlatMapSerializeStructVariantAsMapValue {
map: map,
name: name,
fields: Vec::new(),
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, M> ser::SerializeStructVariant for FlatMapSerializeStructVariantAsMapValue<'a, M>
where M: SerializeMap + 'a
{
type Ok = ();
type Error = M::Error;
fn serialize_field<T: ?Sized>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: Serialize,
{
let value = try!(value.serialize(ContentSerializer::<M::Error>::new()));
self.fields.push((key, value));
Ok(())
}
fn end(self) -> Result<(), Self::Error> {
try!(self.map.serialize_value(&Content::Struct(self.name, self.fields)));
Ok(())
}
}
+67 -1
View File
@@ -96,7 +96,7 @@ where
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(repr="map")]
#[serde(repr = "map")]
struct CollectOther {
a: u32,
b: u32,
@@ -104,6 +104,27 @@ struct CollectOther {
extra: HashMap<String, u32>,
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(repr = "map")]
struct ChangeRequest {
#[serde(flatten)]
data: ChangeAction,
#[serde(flatten)]
extra: HashMap<String, String>,
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
enum ChangeAction {
AppendInteger {
value: u32
},
InsertInteger {
index: u32,
value: u32
},
}
#[test]
fn test_default_struct() {
assert_de_tokens(
@@ -1309,3 +1330,48 @@ fn test_collect_other() {
],
);
}
#[test]
fn test_flatten_struct_enum() {
let mut extra = HashMap::new();
extra.insert("extra_key".into(), "extra value".into());
let change_request = ChangeRequest {
data: ChangeAction::InsertInteger {
index: 0,
value: 42
},
extra: extra,
};
assert_de_tokens(
&change_request,
&[
Token::Map { len: None },
Token::Str("insert_integer"),
Token::Map { len: None },
Token::Str("index"),
Token::U32(0),
Token::Str("value"),
Token::U32(42),
Token::MapEnd,
Token::Str("extra_key"),
Token::String("extra value".into()),
Token::MapEnd
],
);
assert_ser_tokens(
&change_request,
&[
Token::Map { len: None },
Token::Str("insert_integer"),
Token::Struct { len: 2, name: "insert_integer" },
Token::Str("index"),
Token::U32(0),
Token::Str("value"),
Token::U32(42),
Token::StructEnd,
Token::Str("extra_key"),
Token::String("extra value".into()),
Token::MapEnd
],
);
}