From e35603eb855df950598a8fcbfb06d0c5c68629e8 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Wed, 22 Jul 2015 09:47:58 -0700 Subject: [PATCH] Fix serializing maps/sequences with no size hint Closes #101 --- serde_json/src/ser.rs | 11 ++- serde_tests/tests/test_json.rs | 174 ++++++++++++++++++++++++++++++++- 2 files changed, 181 insertions(+), 4 deletions(-) diff --git a/serde_json/src/ser.rs b/serde_json/src/ser.rs index d432c49d..294a7f49 100644 --- a/serde_json/src/ser.rs +++ b/serde_json/src/ser.rs @@ -213,9 +213,11 @@ impl ser::Serializer for Serializer where T: ser::Serialize, { try!(self.formatter.comma(&mut self.writer, self.first)); + try!(value.serialize(self)); + self.first = false; - value.serialize(self) + Ok(()) } #[inline] @@ -261,11 +263,14 @@ impl ser::Serializer for Serializer V: ser::Serialize, { try!(self.formatter.comma(&mut self.writer, self.first)); - self.first = false; try!(key.serialize(self)); try!(self.formatter.colon(&mut self.writer)); - value.serialize(self) + try!(value.serialize(self)); + + self.first = false; + + Ok(()) } #[inline] diff --git a/serde_tests/tests/test_json.rs b/serde_tests/tests/test_json.rs index 0c4ccd65..931527e9 100644 --- a/serde_tests/tests/test_json.rs +++ b/serde_tests/tests/test_json.rs @@ -1,5 +1,6 @@ -use std::fmt::Debug; use std::collections::BTreeMap; +use std::fmt::Debug; +use std::marker::PhantomData; use serde::de; use serde::ser; @@ -1095,3 +1096,174 @@ fn test_lookup() { assert!(obj.lookup("y").unwrap() == &Value::U64(2)); assert!(obj.lookup("z").is_none()); } + +#[test] +fn test_serialize_seq_with_no_len() { + #[derive(Clone, Debug, PartialEq)] + struct MyVec(Vec); + + impl ser::Serialize for MyVec + where T: ser::Serialize, + { + #[inline] + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: ser::Serializer, + { + serializer.visit_seq(ser::impls::SeqIteratorVisitor::new(self.0.iter(), None)) + } + } + + struct Visitor { + marker: PhantomData>, + } + + impl de::Visitor for Visitor + where T: de::Deserialize, + { + type Value = MyVec; + + #[inline] + fn visit_unit(&mut self) -> Result, E> + where E: de::Error, + { + Ok(MyVec(Vec::new())) + } + + #[inline] + fn visit_seq(&mut self, mut visitor: V) -> Result, V::Error> + where V: de::SeqVisitor, + { + let mut values = Vec::new(); + + while let Some(value) = try!(visitor.visit()) { + values.push(value); + } + + try!(visitor.end()); + + Ok(MyVec(values)) + } + } + + impl de::Deserialize for MyVec + where T: de::Deserialize, + { + fn deserialize(deserializer: &mut D) -> Result, D::Error> + where D: de::Deserializer, + { + deserializer.visit_map(Visitor { marker: PhantomData }) + } + } + + let mut vec = Vec::new(); + vec.push(MyVec(Vec::new())); + vec.push(MyVec(Vec::new())); + let vec: MyVec> = MyVec(vec); + + test_encode_ok(&[ + ( + vec.clone(), + "[[],[]]", + ), + ]); + + let s = serde_json::to_string_pretty(&vec).unwrap(); + assert_eq!( + s, + concat!( + "[\n", + " [\n", + " ],\n", + " [\n", + " ]\n", + "]" + ) + ); +} + +#[test] +fn test_serialize_map_with_no_len() { + #[derive(Clone, Debug, PartialEq)] + struct Map(BTreeMap); + + impl ser::Serialize for Map + where K: ser::Serialize + Ord, + V: ser::Serialize, + { + #[inline] + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: ser::Serializer, + { + serializer.visit_map(ser::impls::MapIteratorVisitor::new(self.0.iter(), None)) + } + } + + struct Visitor { + marker: PhantomData>, + } + + impl de::Visitor for Visitor + where K: de::Deserialize + Eq + Ord, + V: de::Deserialize, + { + type Value = Map; + + #[inline] + fn visit_unit(&mut self) -> Result, E> + where E: de::Error, + { + Ok(Map(BTreeMap::new())) + } + + #[inline] + fn visit_map(&mut self, mut visitor: Visitor) -> Result, Visitor::Error> + where Visitor: de::MapVisitor, + { + let mut values = BTreeMap::new(); + + while let Some((key, value)) = try!(visitor.visit()) { + values.insert(key, value); + } + + try!(visitor.end()); + + Ok(Map(values)) + } + } + + impl de::Deserialize for Map + where K: de::Deserialize + Eq + Ord, + V: de::Deserialize, + { + fn deserialize(deserializer: &mut D) -> Result, D::Error> + where D: de::Deserializer, + { + deserializer.visit_map(Visitor { marker: PhantomData }) + } + } + + let mut map = BTreeMap::new(); + map.insert("a", Map(BTreeMap::new())); + map.insert("b", Map(BTreeMap::new())); + let map: Map<_, Map> = Map(map); + + test_encode_ok(&[ + ( + map.clone(), + "{\"a\":{},\"b\":{}}", + ), + ]); + + let s = serde_json::to_string_pretty(&map).unwrap(); + assert_eq!( + s, + concat!( + "{\n", + " \"a\": {\n", + " },\n", + " \"b\": {\n", + " }\n", + "}" + ) + ); +}