From d8fb2abd032ad1907d269c24d518a9695493a34b Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Mon, 9 Jun 2014 07:51:53 -0700 Subject: [PATCH] Change the json enum serialization to {"variant":["fields", ...]} test bench_enum::bench_decoder_dog ... bench: 112 ns/iter (+/- 15) test bench_enum::bench_decoder_frog ... bench: 336 ns/iter (+/- 6) test bench_enum::bench_deserializer_dog ... bench: 120 ns/iter (+/- 4) test bench_enum::bench_deserializer_frog ... bench: 317 ns/iter (+/- 15) test bench_map::bench_decoder_000 ... bench: 528 ns/iter (+/- 13) test bench_map::bench_decoder_003 ... bench: 2459 ns/iter (+/- 74) test bench_map::bench_decoder_100 ... bench: 70756 ns/iter (+/- 1979) test bench_map::bench_deserializer_000 ... bench: 753 ns/iter (+/- 30) test bench_map::bench_deserializer_003 ... bench: 2574 ns/iter (+/- 111) test bench_map::bench_deserializer_100 ... bench: 62374 ns/iter (+/- 1714) test bench_struct::bench_decoder_0_0 ... bench: 609 ns/iter (+/- 14) test bench_struct::bench_decoder_1_0 ... bench: 1620 ns/iter (+/- 44) test bench_struct::bench_decoder_1_5 ... bench: 4393 ns/iter (+/- 88) test bench_struct::bench_deserializer_0_0 ... bench: 699 ns/iter (+/- 10) test bench_struct::bench_deserializer_1_0 ... bench: 2160 ns/iter (+/- 53) test bench_struct::bench_deserializer_1_5 ... bench: 4987 ns/iter (+/- 87) test bench_vec::bench_decoder_int_000 ... bench: 20 ns/iter (+/- 1) test bench_vec::bench_decoder_int_003 ... bench: 148 ns/iter (+/- 3) test bench_vec::bench_decoder_int_100 ... bench: 1009 ns/iter (+/- 44) test bench_vec::bench_decoder_u8_000 ... bench: 16 ns/iter (+/- 0) test bench_vec::bench_decoder_u8_003 ... bench: 152 ns/iter (+/- 12) test bench_vec::bench_decoder_u8_100 ... bench: 1457 ns/iter (+/- 95) test bench_vec::bench_deserializer_int_000 ... bench: 16 ns/iter (+/- 0) test bench_vec::bench_deserializer_int_003 ... bench: 153 ns/iter (+/- 9) test bench_vec::bench_deserializer_int_100 ... bench: 1015 ns/iter (+/- 38) test bench_vec::bench_deserializer_u8_000 ... bench: 16 ns/iter (+/- 1) test bench_vec::bench_deserializer_u8_003 ... bench: 160 ns/iter (+/- 130) test bench_vec::bench_deserializer_u8_100 ... bench: 1225 ns/iter (+/- 112) test json::tests::bench_decoder_large ... bench: 1979093 ns/iter (+/- 67769) test json::tests::bench_decoder_small ... bench: 4644 ns/iter (+/- 208) test json::tests::bench_decoder_streaming_large ... bench: 848383 ns/iter (+/- 96301) test json::tests::bench_decoder_streaming_small ... bench: 1834 ns/iter (+/- 120) test json::tests::bench_deserializer_large ... bench: 1882598 ns/iter (+/- 137262) test json::tests::bench_deserializer_small ... bench: 3945 ns/iter (+/- 161) test json::tests::bench_deserializer_streaming_large ... bench: 990086 ns/iter (+/- 157794) test json::tests::bench_deserializer_streaming_small ... bench: 2135 ns/iter (+/- 211) --- bench_enum.rs | 4 +- de.rs | 47 ++++++---- json.rs | 250 ++++++++++++++++++++------------------------------ 3 files changed, 130 insertions(+), 171 deletions(-) diff --git a/bench_enum.rs b/bench_enum.rs index 05cc88b9..66a43596 100644 --- a/bench_enum.rs +++ b/bench_enum.rs @@ -17,14 +17,14 @@ impl> Deserializable for Animal { fn deserialize_token(d: &mut D, token: Token) -> Result { match try!(d.expect_enum_start(token, "Animal", ["Dog", "Frog"])) { 0 => { - try!(d.expect_end()); + try!(d.expect_enum_end()); Ok(Dog) } 1 => { let x0 = try!(Deserializable::deserialize(d)); let x1 = try!(Deserializable::deserialize(d)); - try!(d.expect_end()); + try!(d.expect_enum_end()); Ok(Frog(x0, x1)) } diff --git a/de.rs b/de.rs index 1c347b92..6118bea9 100644 --- a/de.rs +++ b/de.rs @@ -159,6 +159,14 @@ pub trait Deserializer: Iterator> { } } + #[inline] + fn expect_tuple_end(&mut self) -> Result<(), E> { + match try!(self.expect_token()) { + End => Ok(()), + _ => self.syntax_error(), + } + } + #[inline] fn expect_struct_start(&mut self, token: Token, name: &str) -> Result<(), E> { match token { @@ -194,6 +202,14 @@ pub trait Deserializer: Iterator> { Deserializable::deserialize(self) } + #[inline] + fn expect_struct_end(&mut self) -> Result<(), E> { + match try!(self.expect_token()) { + End => Ok(()), + _ => self.syntax_error(), + } + } + #[inline] fn expect_enum_start(&mut self, token: Token, name: &str, variants: &[&str]) -> Result { match token { @@ -211,6 +227,14 @@ pub trait Deserializer: Iterator> { } } + #[inline] + fn expect_enum_end(&mut self) -> Result<(), E> { + match try!(self.expect_token()) { + End => Ok(()), + _ => self.syntax_error(), + } + } + /* #[inline] fn expect_collection< @@ -246,14 +270,6 @@ pub trait Deserializer: Iterator> { _ => self.syntax_error(), } } - - #[inline] - fn expect_end(&mut self) -> Result<(), E> { - match try!(self.expect_token()) { - End => Ok(()), - _ => self.syntax_error(), - } - } } ////////////////////////////////////////////////////////////////////////////// @@ -473,10 +489,9 @@ macro_rules! impl_deserialize_tuple { $name },)*); - match try!(d.expect_token()) { - End => Ok(result), - _ => d.syntax_error(), - } + try!(d.expect_tuple_end()); + + Ok(result) } } peel!($($name,)*) @@ -714,7 +729,7 @@ mod tests { let a = try!(d.expect_struct_field("a")); let b = try!(d.expect_struct_field("b")); let c = try!(d.expect_struct_field("c")); - try!(d.expect_end()); + try!(d.expect_struct_end()); Ok(Inner { a: a, b: b, c: c }) } } @@ -731,7 +746,7 @@ mod tests { fn deserialize_token(d: &mut D, token: Token) -> Result { try!(d.expect_struct_start(token, "Outer")); let inner = try!(d.expect_struct_field("inner")); - try!(d.expect_end()); + try!(d.expect_struct_end()); Ok(Outer { inner: inner }) } } @@ -749,13 +764,13 @@ mod tests { fn deserialize_token(d: &mut D, token: Token) -> Result { match try!(d.expect_enum_start(token, "Animal", ["Dog", "Frog"])) { 0 => { - try!(d.expect_end()); + try!(d.expect_enum_end()); Ok(Dog) } 1 => { let x0 = try!(Deserializable::deserialize(d)); let x1 = try!(Deserializable::deserialize(d)); - try!(d.expect_end()); + try!(d.expect_enum_end()); Ok(Frog(x0, x1)) } _ => unreachable!(), diff --git a/json.rs b/json.rs index ae47c33c..e3605667 100644 --- a/json.rs +++ b/json.rs @@ -228,7 +228,7 @@ fn main() { */ use std::char; -use std::collections::{Deque, HashMap, RingBuf, TreeMap}; +use std::collections::{HashMap, TreeMap}; use std::collections::treemap; use std::f64; use std::fmt; @@ -293,14 +293,9 @@ impl> de::Deserializable for Json { de::EnumStart(_, name, len) => { let token = de::SeqStart(len); let fields: Vec = try!(de::Deserializable::deserialize_token(d, token)); - if fields.is_empty() { - Ok(String(name.to_string())) - } else { - let mut object = TreeMap::new(); - object.insert("variant".to_string(), String(name.to_string())); - object.insert("fields".to_string(), List(fields)); - Ok(Object(object)) - } + let mut object = TreeMap::new(); + object.insert(name.to_string(), List(fields)); + Ok(Object(object)) } de::End => d.syntax_error(), } @@ -415,10 +410,6 @@ impl de::Deserializer for JsonDeserializer { _name: &str, variants: &[&str]) -> Result { let variant = match token { - de::String(variant) => { - self.stack.push(JsonDeserializerEndState); - variant - } de::MapStart(_) => { let state = match self.stack.pop() { Some(state) => state, @@ -430,39 +421,22 @@ impl de::Deserializer for JsonDeserializer { _ => { fail!("state machine error, expected an object"); } }; - let mut variant = None; - let mut fields = None; - - for (key, value) in iter { - if key.equiv(&"variant") { - match value { - String(v) => { variant = Some(v); } - value => { - return Err(ExpectedError("String".to_string(), - format!("{}", value))) - } - } - } else if key.equiv(&"fields") { - match value { - List(v) => { fields = Some(v); } - value => { - return Err(ExpectedError("List".to_string(), - format!("{}", value))) - } - } - } - } - - let (variant, fields) = match (variant, fields) { - (Some(variant), Some(fields)) => (variant, fields), - (None, _) => { - return Err(MissingFieldError("variant".to_string())) - } - (_, None) => { - return Err(MissingFieldError("fields".to_string())) + let (variant, fields) = match iter.next() { + Some((variant, List(fields))) => (variant, fields), + Some((key, value)) => { + return Err(ExpectedError("List".to_string(), format!("{} => {}", key, value))); } + None => { return Err(MissingFieldError("".to_string())); } }; + // Error out if there are other fields in the enum. + match iter.next() { + Some((key, value)) => { + return Err(ExpectedError("None".to_string(), format!("{} => {}", key, value))); + } + None => { } + } + self.stack.push(JsonDeserializerEndState); for field in fields.move_iter().rev() { @@ -673,20 +647,15 @@ impl<'a> serialize::Encoder for Encoder<'a> { fn emit_enum_variant(&mut self, name: &str, _id: uint, - cnt: uint, + _cnt: uint, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult { - // enums are encoded as strings or objects - // Bunny => "Bunny" - // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]} - if cnt == 0 { - write!(self.wr, "{}", escape_str(name)) - } else { - try!(write!(self.wr, "\\{\"variant\":")); - try!(write!(self.wr, "{}", escape_str(name))); - try!(write!(self.wr, ",\"fields\":[")); - try!(f(self)); - write!(self.wr, "]\\}") - } + // enums are encoded as objects + // Kangaroo(34,"William") => {"Kangaroo": [34,"William"]} + try!(write!(self.wr, "\\{")); + try!(write!(self.wr, "{}", escape_str(name))); + try!(write!(self.wr, ":[")); + try!(f(self)); + write!(self.wr, "]\\}") } fn emit_enum_variant_arg(&mut self, @@ -872,15 +841,20 @@ impl<'a> serialize::Encoder for PrettyEncoder<'a> { _: uint, cnt: uint, f: |&mut PrettyEncoder<'a>| -> EncodeResult) -> EncodeResult { + // enums are encoded as objects + // Kangaroo(34,"William") => {"Kangaroo": [34,"William"]} if cnt == 0 { - write!(self.wr, "{}", escape_str(name)) + write!(self.wr, "\\{{}: []\\}", escape_str(name)) } else { self.indent += 2; - try!(write!(self.wr, "[\n{}{},\n", spaces(self.indent), + try!(write!(self.wr, "\\{\n{}{}: [\n", spaces(self.indent), escape_str(name))); + self.indent += 2; try!(f(self)); self.indent -= 2; - write!(self.wr, "\n{}]", spaces(self.indent)) + try!(write!(self.wr, "\n{}]", spaces(self.indent))); + self.indent -= 2; + write!(self.wr, "\n{}\\}", spaces(self.indent)) } } @@ -1394,20 +1368,13 @@ pub struct Parser { line: uint, col: uint, // A state machine is kept to make it possible to interupt and resume parsing. - state: Vec, - tokens: RingBuf, + state_stack: Vec, } impl> Iterator> for Parser { #[inline] fn next(&mut self) -> Option> { - // If we've cached any tokens return them now. - match self.tokens.pop_front() { - Some(token) => { return Some(Ok(token)); } - None => { } - } - - let state = match self.state.pop() { + let state = match self.state_stack.pop() { Some(state) => state, None => { // If we have no state left, then we're expecting the structure @@ -1443,8 +1410,7 @@ impl> Parser { ch: Some('\x00'), line: 1, col: 0, - state: vec!(ParseValue), - tokens: RingBuf::new(), + state_stack: vec!(ParseValue), }; p.bump(); return p; @@ -1704,7 +1670,7 @@ impl> Parser { self.bump(); Ok(de::End) } else { - self.state.push(ParseListCommaOrEnd); + self.state_stack.push(ParseListCommaOrEnd); self.parse_value() } } @@ -1714,7 +1680,7 @@ impl> Parser { if self.ch_is(',') { self.bump(); - self.state.push(ParseListCommaOrEnd); + self.state_stack.push(ParseListCommaOrEnd); self.parse_value() } else if self.ch_is(']') { self.bump(); @@ -1756,7 +1722,7 @@ impl> Parser { fn parse_object_key(&mut self) -> Result { self.parse_whitespace(); - self.state.push(ParseObjectValue); + self.state_stack.push(ParseObjectValue); if self.eof() { return self.error_event(EOFWhileParsingString); @@ -1776,7 +1742,7 @@ impl> Parser { if self.ch_is(':') { self.bump(); - self.state.push(ParseObjectCommaOrEnd); + self.state_stack.push(ParseObjectCommaOrEnd); self.parse_value() } else if self.eof() { self.error_event(EOFWhileParsingObject) @@ -1806,12 +1772,12 @@ impl> Parser { } '[' => { self.bump(); - self.state.push(ParseListStart); + self.state_stack.push(ParseListStart); Ok(de::SeqStart(0)) } '{' => { self.bump(); - self.state.push(ParseObjectStart); + self.state_stack.push(ParseObjectStart); Ok(de::MapStart(0)) } _ => { @@ -1820,17 +1786,17 @@ impl> Parser { } } - fn parse_ident(&mut self, ident: &str, value: de::Token) -> Result { + fn parse_ident(&mut self, ident: &str, token: de::Token) -> Result { if ident.chars().all(|c| Some(c) == self.next_char()) { self.bump(); - Ok(value) + Ok(token) } else { - Err(SyntaxError(InvalidSyntax, self.line, self.col)) + self.error_event(InvalidSyntax) } } fn error_event(&mut self, reason: ErrorCode) -> Result { - self.state.clear(); + self.state_stack.clear(); Err(SyntaxError(reason, self.line, self.col)) } } @@ -1858,75 +1824,47 @@ impl> de::Deserializer for Parser { } } - // Special case treating enums as a String or a `{"variant": "...", "fields": [...]}`. + // Special case treating enums as a `{"": []}`. #[inline] fn expect_enum_start(&mut self, token: de::Token, _name: &str, variants: &[&str]) -> Result { - // It's a little tricky to deserialize enums. Strings are simple to - // parse, but objects require us to preparse the entire object because - // we can't guarantee the order of the map. - - let variant = match token { - de::String(variant) => { - // Make sure to terminate the enum. - self.tokens.push_front(de::End); - - variant - } - de::MapStart(_len) => { - let mut variant = None; - let mut fields = None; - - // Extract all the fields. - loop { - let field = match try!(self.expect_token()) { - de::End => { break; } - de::String(field) => field, - _ => { return self.error(InvalidSyntax); } - }; - - match field.as_slice() { - "variant" => { - let v: String = try!(de::Deserializable::deserialize(self)); - variant = Some(v); - } - "fields" => { - let f: de::GatherTokens = try!(de::Deserializable::deserialize(self)); - fields = Some(f.unwrap()); - } - _ => { } - } - } - - let (variant, fields) = match (variant, fields) { - (Some(variant), Some(fields)) => (variant, fields), - _ => { return self.error(MissingField); } - }; - - // Add all the field's tokens to our buffer. We need to skip - // over the `SeqStart` because we're pretending we're an - // `EnumStart`. - let mut iter = fields.move_iter(); - match iter.next() { - Some(de::SeqStart(_)) => { } - _ => { return self.error(InvalidSyntax); } - } - self.tokens.extend(iter); - - variant - } + match token { + de::MapStart(_) => { } _ => { return self.error(InvalidSyntax); } }; + // Enums only have one field in them, which is the variant name. + let variant = match try!(self.expect_token()) { + de::String(variant) => variant, + _ => { return self.error(InvalidSyntax); } + }; + + // The variant's field is a list of the values. + match try!(self.expect_token()) { + de::SeqStart(_) => { } + _ => { return self.error(InvalidSyntax); } + } + match variants.iter().position(|v| *v == variant.as_slice()) { - Some(idx) => { - Ok(idx) - } + Some(idx) => Ok(idx), None => self.error(UnknownVariant), } } + + fn expect_enum_end(&mut self) -> Result<(), ParserError> { + // There will be one `End` for the list, and one for the object. + match try!(self.expect_token()) { + de::End => { + match try!(self.expect_token()) { + de::End => Ok(()), + _ => self.error(InvalidSyntax), + } + } + _ => self.error(InvalidSyntax), + } + } } /* @@ -2582,14 +2520,14 @@ mod tests { fn deserialize_token(d: &mut D, token: de::Token) -> Result { match try!(d.expect_enum_start(token, "Animal", ["Dog", "Frog"])) { 0 => { - try!(d.expect_end()); + try!(d.expect_enum_end()); Ok(Dog) } 1 => { let x0 = try!(de::Deserializable::deserialize(d)); let x1 = try!(de::Deserializable::deserialize(d)); - try!(d.expect_end()); + try!(d.expect_enum_end()); Ok(Frog(x0, x1)) } @@ -2601,12 +2539,17 @@ mod tests { impl ToJson for Animal { fn to_json(&self) -> Json { match *self { - Dog => String("Dog".to_string()), + Dog => { + Object( + treemap!( + "Dog".to_string() => List(vec!()) + ) + ) + } Frog(ref x0, x1) => { Object( treemap!( - "variant".to_string() => "Frog".to_json(), - "fields".to_string() => List(vec!(x0.to_json(), x1.to_json())) + "Frog".to_string() => List(vec!(x0.to_json(), x1.to_json())) ) ) } @@ -2905,14 +2848,14 @@ mod tests { let mut encoder = Encoder::new(wr); animal.encode(&mut encoder).unwrap(); }), - "\"Dog\"".to_string() + "{\"Dog\":[]}".to_string() ); assert_eq!( with_str_writer(|wr| { let mut encoder = PrettyEncoder::new(wr); animal.encode(&mut encoder).unwrap(); }), - "\"Dog\"".to_string() + "{\"Dog\": []}".to_string() ); let animal = Frog("Henry".to_string(), 349); @@ -2921,7 +2864,7 @@ mod tests { let mut encoder = Encoder::new(wr); animal.encode(&mut encoder).unwrap(); }), - "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}".to_string() + "{\"Frog\":[\"Henry\",349]}".to_string() ); assert_eq!( with_str_writer(|wr| { @@ -2929,11 +2872,12 @@ mod tests { animal.encode(&mut encoder).unwrap(); }), "\ - [\n \ - \"Frog\",\n \ - \"Henry\",\n \ - 349\n\ - ]".to_string() + {\n \ + \"Frog\": [\n \ + \"Henry\",\n \ + 349\n \ + ]\n\ + }".to_string() ); } @@ -3293,16 +3237,16 @@ mod tests { #[test] fn test_parse_enum() { test_parse_ok([ - ("\"Dog\"", Dog), + ("{\"Dog\": []}", Dog), ( - "{\"variant\": \"Frog\", \"fields\": [\"Henry\", 349]}", + "{\"Frog\": [\"Henry\", 349]}", Frog("Henry".to_string(), 349), ), ]); test_parse_ok([ ( - "{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\"fields\":[\"Henry\", 349]}}", + "{\"a\": {\"Dog\": []}, \"b\": {\"Frog\":[\"Henry\", 349]}}", treemap!( "a".to_string() => Dog, "b".to_string() => Frog("Henry".to_string(), 349)