From 24787195a11af5cc6fb67c027a75e16a336bed90 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 17 Jul 2015 15:19:11 +0200 Subject: [PATCH] serialize tuple enums with single element directly as the value instead of a sequence --- serde/src/ser/mod.rs | 8 ++++++++ serde_codegen/src/ser.rs | 20 +++++++++++++++++++- serde_json/src/ser.rs | 16 ++++++++++++++++ serde_json/src/value.rs | 16 ++++++++++++++++ serde_tests/tests/test_bytes.rs | 9 +++++++++ serde_tests/tests/test_json.rs | 10 +++++++++- serde_tests/tests/test_macros.rs | 4 ++-- serde_tests/tests/test_ser.rs | 15 +++++++++++++++ 8 files changed, 94 insertions(+), 4 deletions(-) diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index d816dc35..4484d344 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -125,6 +125,14 @@ pub trait Serializer { self.visit_unit() } + #[inline] + fn visit_enum_simple(&mut self, + _name: &str, + _variant: &str, + _value: T, + ) -> Result<(), Self::Error> + where T: Serialize; + fn visit_none(&mut self) -> Result<(), Self::Error>; fn visit_some(&mut self, value: V) -> Result<(), Self::Error> diff --git a/serde_codegen/src/ser.rs b/serde_codegen/src/ser.rs index 8c74e119..fb48eb25 100644 --- a/serde_codegen/src/ser.rs +++ b/serde_codegen/src/ser.rs @@ -296,7 +296,25 @@ fn serialize_variant( ) } ) - } + }, + ast::TupleVariantKind(ref args) if args.len() == 1 => { + let field = builder.id("__simple_value"); + let field = builder.pat().ref_id(field); + let pat = builder.pat().enum_() + .id(type_ident).id(variant_ident).build() + .with_pats(Some(field).into_iter()) + .build(); + quote_arm!(cx, + $pat => { + ::serde::ser::Serializer::visit_enum_simple( + serializer, + $type_name, + $variant_name, + __simple_value, + ) + } + ) + }, ast::TupleVariantKind(ref args) => { let fields: Vec = (0 .. args.len()) .map(|i| builder.id(format!("__field{}", i))) diff --git a/serde_json/src/ser.rs b/serde_json/src/ser.rs index 294a7f49..b7f5b2d8 100644 --- a/serde_json/src/ser.rs +++ b/serde_json/src/ser.rs @@ -171,6 +171,22 @@ impl ser::Serializer for Serializer self.formatter.close(&mut self.writer, b'}') } + #[inline] + fn visit_enum_simple(&mut self, + _name: &str, + variant: &str, + value: T, + ) -> io::Result<()> + where T: ser::Serialize, + { + try!(self.formatter.open(&mut self.writer, b'{')); + try!(self.formatter.comma(&mut self.writer, true)); + try!(self.visit_str(variant)); + try!(self.formatter.colon(&mut self.writer)); + try!(value.serialize(self)); + self.formatter.close(&mut self.writer, b'}') + } + #[inline] fn visit_seq(&mut self, mut visitor: V) -> io::Result<()> where V: ser::SeqVisitor, diff --git a/serde_json/src/value.rs b/serde_json/src/value.rs index 2cee4427..f1623af2 100644 --- a/serde_json/src/value.rs +++ b/serde_json/src/value.rs @@ -471,6 +471,22 @@ impl ser::Serializer for Serializer { Ok(()) } + #[inline] + fn visit_enum_simple(&mut self, + _name: &str, + variant: &str, + value: T, + ) -> Result<(), ()> + where T: ser::Serialize, + { + let mut values = BTreeMap::new(); + values.insert(variant.to_string(), to_value(&value)); + + self.state.push(State::Value(Value::Object(values))); + + Ok(()) + } + #[inline] fn visit_seq(&mut self, mut visitor: V) -> Result<(), ()> where V: ser::SeqVisitor, diff --git a/serde_tests/tests/test_bytes.rs b/serde_tests/tests/test_bytes.rs index 3ca97285..65c466a3 100644 --- a/serde_tests/tests/test_bytes.rs +++ b/serde_tests/tests/test_bytes.rs @@ -39,6 +39,15 @@ impl serde::Serializer for BytesSerializer { Err(Error) } + fn visit_enum_simple(&mut self, + _name: &str, + _variant: &str, + _value: T, + ) -> Result<(), Error> + { + Err(Error) + } + fn visit_bool(&mut self, _v: bool) -> Result<(), Error> { Err(Error) } diff --git a/serde_tests/tests/test_json.rs b/serde_tests/tests/test_json.rs index 931527e9..14345a28 100644 --- a/serde_tests/tests/test_json.rs +++ b/serde_tests/tests/test_json.rs @@ -28,7 +28,7 @@ enum Animal { Dog, Frog(String, Vec), Cat { age: usize, name: String }, - + AntHive(Vec), } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -534,6 +534,10 @@ fn test_write_enum() { Animal::Cat { age: 5, name: "Kate".to_string() }, "{\"Cat\":{\"age\":5,\"name\":\"Kate\"}}" ), + ( + Animal::AntHive(vec!["Bob".to_string(), "Stuart".to_string()]), + "{\"AntHive\":[\"Bob\",\"Stuart\"]}", + ), ]); test_pretty_encode_ok(&[ @@ -976,6 +980,10 @@ fn test_parse_enum() { " { \"Cat\" : { \"age\" : 5 , \"name\" : \"Kate\" } } ", Animal::Cat { age: 5, name: "Kate".to_string() }, ), + ( + " { \"AntHive\" : [\"Bob\", \"Stuart\"] } ", + Animal::AntHive(vec!["Bob".to_string(), "Stuart".to_string()]), + ), ]); test_parse_ok(vec![ diff --git a/serde_tests/tests/test_macros.rs b/serde_tests/tests/test_macros.rs index 3c41ca4c..9b8d43df 100644 --- a/serde_tests/tests/test_macros.rs +++ b/serde_tests/tests/test_macros.rs @@ -473,13 +473,13 @@ fn test_lifetimes() { let lifetime = Lifetimes::LifetimeSeq(&value); assert_eq!( serde_json::to_string(&lifetime).unwrap(), - "{\"LifetimeSeq\":[5]}" + "{\"LifetimeSeq\":5}" ); let lifetime = Lifetimes::NoLifetimeSeq(5); assert_eq!( serde_json::to_string(&lifetime).unwrap(), - "{\"NoLifetimeSeq\":[5]}" + "{\"NoLifetimeSeq\":5}" ); let value = 5; diff --git a/serde_tests/tests/test_ser.rs b/serde_tests/tests/test_ser.rs index 950b5b82..62627fba 100644 --- a/serde_tests/tests/test_ser.rs +++ b/serde_tests/tests/test_ser.rs @@ -27,6 +27,8 @@ pub enum Token<'a> { UnitStruct(&'a str), EnumUnit(&'a str, &'a str), + EnumSimple(&'a str, &'a str), + SeqStart(Option), TupleStructStart(&'a str, Option), EnumSeqStart(&'a str, &'a str, Option), @@ -80,6 +82,17 @@ impl<'a> Serializer for AssertSerializer<'a> { Ok(()) } + fn visit_enum_simple(&mut self, + name: &str, + variant: &str, + value: T, + ) -> Result<(), ()> + where T: Serialize, + { + assert_eq!(self.iter.next(), Some(Token::EnumSimple(name, variant))); + value.serialize(self) + } + fn visit_unit_struct(&mut self, name: &str) -> Result<(), ()> { assert_eq!(self.iter.next().unwrap(), Token::UnitStruct(name)); Ok(()) @@ -301,6 +314,7 @@ struct Struct { #[derive(Serialize)] enum Enum { Unit, + One(i32), Seq(i32, i32), Map { a: i32, b: i32 }, } @@ -554,6 +568,7 @@ declare_tests! { } test_enum { Enum::Unit => vec![Token::EnumUnit("Enum", "Unit")], + Enum::One(42) => vec![Token::EnumSimple("Enum", "One"), Token::I32(42)], Enum::Seq(1, 2) => vec![ Token::EnumSeqStart("Enum", "Seq", Some(2)), Token::SeqSep,