From 58851118636626c2f445c3ce48adbbcccc73257f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 14 Jul 2015 11:12:01 +0200 Subject: [PATCH 1/4] deserialize tuple enums with single element directly as the value instead of a sequence --- serde/src/de/mod.rs | 9 +++ serde_codegen/src/de.rs | 6 ++ serde_json/src/de.rs | 12 ++-- serde_json/src/value.rs | 151 +++++++++++++++++++--------------------- 4 files changed, 91 insertions(+), 87 deletions(-) diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs index 5484a7b7..2f3c6a30 100644 --- a/serde/src/de/mod.rs +++ b/serde/src/de/mod.rs @@ -571,6 +571,11 @@ pub trait VariantVisitor { Err(Error::syntax_error()) } + /// `visit_simple` is called when deserializing a variant with a single value. + fn visit_simple(&mut self) -> Result { + Err(Error::syntax_error()) + } + /// `visit_seq` is called when deserializing a tuple-like variant. fn visit_seq(&mut self, _visitor: V) -> Result where V: Visitor @@ -601,6 +606,10 @@ impl<'a, T> VariantVisitor for &'a mut T where T: VariantVisitor { (**self).visit_unit() } + fn visit_simple(&mut self) -> Result { + (**self).visit_simple() + } + fn visit_seq(&mut self, visitor: V) -> Result where V: Visitor, { diff --git a/serde_codegen/src/de.rs b/serde_codegen/src/de.rs index 3f949df0..90f7d7ff 100644 --- a/serde_codegen/src/de.rs +++ b/serde_codegen/src/de.rs @@ -555,6 +555,12 @@ fn deserialize_variant( Ok($type_ident::$variant_ident) }) } + ast::TupleVariantKind(ref args) if args.len() == 1 => { + quote_expr!(cx, { + let val = try!(visitor.visit_simple()); + Ok($type_ident::$variant_ident(val)) + }) + } ast::TupleVariantKind(ref args) => { deserialize_tuple_variant( cx, diff --git a/serde_json/src/de.rs b/serde_json/src/de.rs index 8bb33931..efdd53df 100644 --- a/serde_json/src/de.rs +++ b/serde_json/src/de.rs @@ -632,20 +632,22 @@ impl de::VariantVisitor for Deserializer fn visit_variant(&mut self) -> Result where V: de::Deserialize { - de::Deserialize::deserialize(self) + let val = try!(de::Deserialize::deserialize(self)); + try!(self.parse_object_colon()); + Ok(val) } fn visit_unit(&mut self) -> Result<(), Error> { - try!(self.parse_object_colon()); + de::Deserialize::deserialize(self) + } + fn visit_simple(&mut self) -> Result { de::Deserialize::deserialize(self) } fn visit_seq(&mut self, visitor: V) -> Result where V: de::Visitor, { - try!(self.parse_object_colon()); - de::Deserializer::visit(self, visitor) } @@ -654,8 +656,6 @@ impl de::VariantVisitor for Deserializer visitor: V) -> Result where V: de::Visitor, { - try!(self.parse_object_colon()); - de::Deserializer::visit(self, visitor) } } diff --git a/serde_json/src/value.rs b/serde_json/src/value.rs index 45cb7785..2cee4427 100644 --- a/serde_json/src/value.rs +++ b/serde_json/src/value.rs @@ -687,33 +687,19 @@ impl de::Deserializer for Deserializer { let mut iter = value.into_iter(); - let value = match iter.next() { - Some((variant, Value::Array(fields))) => { - self.value = Some(Value::String(variant)); - - let len = fields.len(); - try!(visitor.visit(SeqDeserializer { - de: self, - iter: fields.into_iter(), - len: len, - })) - } - Some((variant, Value::Object(fields))) => { - let len = fields.len(); - try!(visitor.visit(MapDeserializer { - de: self, - iter: fields.into_iter(), - value: Some(Value::String(variant)), - len: len, - })) - } - Some(_) => { return Err(de::Error::syntax_error()); } - None => { return Err(de::Error::syntax_error()); } + let (variant, value) = match iter.next() { + Some(v) => v, + None => return Err(de::Error::syntax_error()), }; + // enums are encoded in json as maps with a single key:value pair match iter.next() { Some(_) => Err(de::Error::syntax_error()), - None => Ok(value) + None => visitor.visit(VariantDeserializer { + de: self, + val: Some(value), + variant: Some(Value::String(variant)), + }), } } @@ -723,6 +709,67 @@ impl de::Deserializer for Deserializer { } } +struct VariantDeserializer<'a> { + de: &'a mut Deserializer, + val: Option, + variant: Option, +} + +impl<'a> de::VariantVisitor for VariantDeserializer<'a> { + type Error = Error; + + fn visit_variant(&mut self) -> Result + where V: de::Deserialize, + { + de::Deserialize::deserialize(&mut Deserializer::new(self.variant.take().unwrap())) + } + + fn visit_unit(&mut self) -> Result<(), Error> + { + de::Deserialize::deserialize(&mut Deserializer::new(self.val.take().unwrap())) + } + + fn visit_simple(&mut self) -> Result + { + de::Deserialize::deserialize(&mut Deserializer::new(self.val.take().unwrap())) + } + + fn visit_seq(&mut self, visitor: V) -> Result + where V: de::Visitor, + { + if let Value::Array(fields) = self.val.take().unwrap() { + de::Deserializer::visit( + &mut SeqDeserializer { + de: self.de, + len: fields.len(), + iter: fields.into_iter(), + }, + visitor, + ) + } else { + Err(de::Error::syntax_error()) + } + } + + fn visit_map(&mut self, visitor: V) -> Result + where V: de::Visitor, + { + if let Value::Object(fields) = self.val.take().unwrap() { + de::Deserializer::visit( + &mut MapDeserializer { + de: self.de, + len: fields.len(), + iter: fields.into_iter(), + value: None, + }, + visitor, + ) + } else { + Err(de::Error::syntax_error()) + } + } +} + struct SeqDeserializer<'a> { de: &'a mut Deserializer, iter: vec::IntoIter, @@ -773,35 +820,6 @@ impl<'a> de::SeqVisitor for SeqDeserializer<'a> { } } -impl<'a> de::VariantVisitor for SeqDeserializer<'a> { - type Error = Error; - - fn visit_variant(&mut self) -> Result - where V: de::Deserialize, - { - de::Deserialize::deserialize(self.de) - } - - fn visit_unit(&mut self) -> Result<(), Error> - { - de::Deserialize::deserialize(self) - } - - fn visit_seq(&mut self, visitor: V) -> Result - where V: de::Visitor, - { - de::Deserializer::visit(self, visitor) - } - - fn visit_map(&mut self, - _fields: &'static [&'static str], - visitor: V) -> Result - where V: de::Visitor, - { - de::Deserializer::visit(self, visitor) - } -} - struct MapDeserializer<'a> { de: &'a mut Deserializer, iter: btree_map::IntoIter, @@ -884,35 +902,6 @@ impl<'a> de::Deserializer for MapDeserializer<'a> { } } -impl<'a> de::VariantVisitor for MapDeserializer<'a> { - type Error = Error; - - fn visit_variant(&mut self) -> Result - where V: de::Deserialize, - { - self.de.value = self.value.take(); - de::Deserialize::deserialize(self.de) - } - - fn visit_unit(&mut self) -> Result<(), Error> { - de::Deserialize::deserialize(self) - } - - fn visit_seq(&mut self, visitor: V) -> Result - where V: de::Visitor, - { - de::Deserializer::visit(self, visitor) - } - - fn visit_map(&mut self, - _fields: &'static [&'static str], - visitor: V) -> Result - where V: de::Visitor, - { - de::Deserializer::visit(self, visitor) - } -} - /// Shortcut function to encode a `T` into a JSON `Value` pub fn to_value(value: &T) -> Value where T: ser::Serialize From 24787195a11af5cc6fb67c027a75e16a336bed90 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 17 Jul 2015 15:19:11 +0200 Subject: [PATCH 2/4] 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, From 8f8fc6f3fff1040b4cfa58a0d0f7565b3aaa8c1a Mon Sep 17 00:00:00 2001 From: Oliver 'ker' Schneider Date: Thu, 23 Jul 2015 18:37:26 +0200 Subject: [PATCH 3/4] nits and rebase fallout --- serde_json/src/lib.rs | 6 +++--- serde_json/src/value.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/serde_json/src/lib.rs b/serde_json/src/lib.rs index 2e13f2a4..3032db9c 100644 --- a/serde_json/src/lib.rs +++ b/serde_json/src/lib.rs @@ -61,12 +61,12 @@ //! //#![feature(custom_derive, plugin)] //! //#![plugin(serde_macros)] //! -//! extern crate serde; +//! extern crate serde_json; //! -//! use serde_json::{self, Value}; +//! use serde_json::Value; //! //! fn main() { -//! let data: Value = json::from_str("{\"foo\": 13, \"bar\": \"baz\"}").unwrap(); +//! let data: Value = serde_json::from_str("{\"foo\": 13, \"bar\": \"baz\"}").unwrap(); //! println!("data: {:?}", data); //! // data: {"bar":"baz","foo":13} //! println!("object? {}", data.is_object()); diff --git a/serde_json/src/value.rs b/serde_json/src/value.rs index f1623af2..f01dfe1d 100644 --- a/serde_json/src/value.rs +++ b/serde_json/src/value.rs @@ -767,7 +767,7 @@ impl<'a> de::VariantVisitor for VariantDeserializer<'a> { } } - fn visit_map(&mut self, visitor: V) -> Result + fn visit_map(&mut self, _fields: &'static[&'static str], visitor: V) -> Result where V: de::Visitor, { if let Value::Object(fields) = self.val.take().unwrap() { From 5f1cb9b96c15eb7b2034290960e7a1ac9dd88927 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 24 Jul 2015 09:31:35 +0200 Subject: [PATCH 4/4] rebased again --- serde_tests/tests/test_macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/serde_tests/tests/test_macros.rs b/serde_tests/tests/test_macros.rs index 9b8d43df..c36e086e 100644 --- a/serde_tests/tests/test_macros.rs +++ b/serde_tests/tests/test_macros.rs @@ -515,8 +515,8 @@ fn test_generic() { declare_tests!( GenericStruct : GenericStruct { x: 5 } => "{\"x\":5}", GenericTupleStruct : GenericTupleStruct(5) => "[5]", - GenericEnumSeq : GenericEnumSeq::Ok(5) => "{\"Ok\":[5]}", - GenericEnumSeq : GenericEnumSeq::Err(5) => "{\"Err\":[5]}", + GenericEnumSeq : GenericEnumSeq::Ok(5) => "{\"Ok\":5}", + GenericEnumSeq : GenericEnumSeq::Err(5) => "{\"Err\":5}", GenericEnumMap : GenericEnumMap::Ok { x: 5 } => "{\"Ok\":{\"x\":5}}", GenericEnumMap : GenericEnumMap::Err { x: 5 } => "{\"Err\":{\"x\":5}}", );