diff --git a/serde_macros/src/lib.rs b/serde_macros/src/lib.rs index 20e2247e..9ea76289 100644 --- a/serde_macros/src/lib.rs +++ b/serde_macros/src/lib.rs @@ -288,128 +288,57 @@ fn deserialize_struct( deserializer: P, token: P ) -> P { - let serial_names: Vec> = - definitions.iter().map(|def| - find_serial_name(def.node.attrs.iter()) - ).collect(); + let type_name_str = cx.expr_str(span, token::get_ident(type_ident)); - let struct_block = deserialize_struct_from_struct( - cx, - span, - type_ident, - serial_names.as_slice(), - fields, - deserializer.clone() - ); - - let map_block = deserialize_struct_from_map( - cx, - span, - type_ident, - serial_names.as_slice(), - fields, - deserializer.clone() - ); - - quote_expr!( - cx, - match $token { - ::serde::de::StructStart(_, _) => $struct_block, - ::serde::de::MapStart(_) => $map_block, - token => { - let expected_tokens = [ - ::serde::de::StructStartKind, - ::serde::de::MapStartKind, - ]; - Err($deserializer.syntax_error(token, expected_tokens)) - } - } - ) -} - -fn deserialize_struct_from_struct( - cx: &ExtCtxt, - span: Span, - type_ident: Ident, - serial_names: &[Option], - fields: &StaticFields, - deserializer: P -) -> P { - //let expect_struct_field = cx.ident_of("expect_struct_field"); - - let call = deserializable_static_fields( - cx, - span, - type_ident, - serial_names.as_slice(), - fields, - |cx, span, name| { - let name = cx.expr_str(span, name); - quote_expr!( - cx, - try!($deserializer.expect_struct_field($name)) - ) - } - ); - - quote_expr!(cx, { - let result = $call; - try!($deserializer.expect_struct_end()); - Ok(result) - }) -} - -fn deserialize_struct_from_map( - cx: &ExtCtxt, - span: Span, - type_ident: Ident, - serial_names: &[Option], - fields: &StaticFields, - deserializer: P -) -> P { let fields = match *fields { Unnamed(_) => fail!(), Named(ref fields) => fields.as_slice(), }; - // Declare each field. - let let_fields: Vec> = fields.iter() - .map(|&(name, _)| { - quote_stmt!(cx, let mut $name = None) + // Convert each field into a unique ident. + let field_idents: Vec = fields.iter() + .enumerate() + .map(|(idx, _)| { + cx.ident_of(format!("field{}", idx).as_slice()) }) .collect(); + // Convert each field into their string. + let field_strs: Vec> = fields.iter() + .zip(definitions.iter()) + .map(|(&(name, _), def)| { + match find_serial_name(def.node.attrs.iter()) { + Some(serial) => cx.expr_str(span, serial), + None => cx.expr_str(span, token::get_ident(name)), + } + }) + .collect(); + + // Declare the static vec slice of field names. + let static_fields = cx.expr_vec_slice(span, field_strs.clone()); + + // Declare each field. + let let_fields: Vec> = field_idents.iter() + .map(|ident| quote_stmt!(cx, let mut $ident = None)) + .collect(); + // Declare key arms. - let key_arms: Vec = serial_names.iter() - .zip(fields.iter()) - .map(|(serial, &(name, span))| { - let serial_name = match serial { - &Some(ref string) => string.clone(), - &None => token::get_ident(name), - }; - let s = cx.expr_str(span, serial_name); + let idx_arms: Vec = field_idents.iter() + .enumerate() + .map(|(idx, ident)| { quote_arm!(cx, - $s => { - $name = Some( - try!(::serde::de::Deserializable::deserialize($deserializer)) - ); - continue; - }) + Some($idx) => { $ident = Some(try!($deserializer.expect_struct_value())); } + ) }) .collect(); - let extract_fields: Vec> = serial_names.iter() - .zip(fields.iter()) - .map(|(serial, &(name, span))| { - let serial_name = match serial { - &Some(ref string) => string.clone(), - &None => token::get_ident(name), - }; - let name_str = cx.expr_str(span, serial_name); + let extract_fields: Vec> = field_idents.iter() + .zip(field_strs.iter()) + .map(|(ident, field_str)| { quote_stmt!(cx, - let $name = match $name { - Some($name) => $name, - None => try!($deserializer.missing_field($name_str)), + let $ident = match $ident { + Some($ident) => $ident, + None => try!($deserializer.missing_field($field_str)), }; ) }) @@ -419,41 +348,34 @@ fn deserialize_struct_from_map( span, type_ident, fields.iter() - .map(|&(name, span)| { - cx.field_imm(span, name, cx.expr_ident(span, name)) + .zip(field_idents.iter()) + .map(|(&(name, _), ident)| { + cx.field_imm(span, name, cx.expr_ident(span, *ident)) }) .collect() ); quote_expr!(cx, { + try!($deserializer.expect_struct_start($token, $type_name_str)); + + static FIELDS: &'static [&'static str] = $static_fields; $let_fields loop { - let token = match try!($deserializer.expect_token()) { - ::serde::de::End => { break; } - token => token, + let idx = match try!($deserializer.expect_struct_field_or_end(FIELDS)) { + Some(idx) => idx, + None => { break; } }; - { - let key = match token { - ::serde::de::Str(s) => s, - ::serde::de::String(ref s) => s.as_slice(), - token => { - let expected_tokens = [ - ::serde::de::StrKind, - ::serde::de::StringKind, - ]; - return Err($deserializer.syntax_error(token, expected_tokens)); - } - }; - - match key { - $key_arms - _ => { } + match idx { + $idx_arms + Some(_) => unreachable!(), + None => { + let _: ::serde::de::IgnoreTokens = + try!(::serde::de::Deserializable::deserialize($deserializer)); } } - - try!($deserializer.ignore_field(token)) + //try!($deserializer.ignore_field(token)) } $extract_fields diff --git a/src/de.rs b/src/de.rs index df539a72..eea56021 100644 --- a/src/de.rs +++ b/src/de.rs @@ -356,25 +356,29 @@ pub trait Deserializer: Iterator> { } #[inline] - fn expect_struct_field< - T: Deserializable - >(&mut self, name: &str) -> Result { + fn expect_struct_field_or_end(&mut self, + fields: &'static [&'static str] + ) -> Result>, E> { match try!(self.expect_token()) { + End => { + Ok(None) + } Str(n) => { - if name != n { - return Err(self.unexpected_name_error(Str(n))); - } + Ok(Some(fields.iter().position(|field| **field == n))) } String(n) => { - if name != n.as_slice() { - return Err(self.unexpected_name_error(String(n))); - } + Ok(Some(fields.iter().position(|field| **field == n.as_slice()))) } token => { - return Err(self.syntax_error(token, STR_TOKEN_KINDS)); + Err(self.syntax_error(token, STR_TOKEN_KINDS)) } } + } + #[inline] + fn expect_struct_value< + T: Deserializable + >(&mut self) -> Result { Deserializable::deserialize(self) } @@ -982,7 +986,7 @@ mod tests { use std::{option, string}; use serialize::Decoder; - use super::{Deserializer, Deserializable, Token, TokenKind}; + use super::{Deserializer, Deserializable, Token, TokenKind, IgnoreTokens}; use super::{ Null, Bool, @@ -1034,11 +1038,29 @@ mod tests { #[inline] fn deserialize_token(d: &mut D, token: Token) -> Result { try!(d.expect_struct_start(token, "Inner")); - 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_struct_end()); - Ok(Inner { a: a, b: b, c: c }) + + let mut a = None; + let mut b = None; + let mut c = None; + + static FIELDS: &'static [&'static str] = &["a", "b", "c"]; + + loop { + let idx = match try!(d.expect_struct_field_or_end(FIELDS)) { + Some(idx) => idx, + None => { break; } + }; + + match idx { + Some(0) => { a = Some(try!(d.expect_struct_value())); } + Some(1) => { b = Some(try!(d.expect_struct_value())); } + Some(2) => { c = Some(try!(d.expect_struct_value())); } + Some(_) => unreachable!(), + None => { let _: IgnoreTokens = try!(Deserializable::deserialize(d)); } + } + } + + Ok(Inner { a: a.unwrap(), b: b.unwrap(), c: c.unwrap() }) } } @@ -1053,9 +1075,25 @@ mod tests { #[inline] 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_struct_end()); - Ok(Outer { inner: inner }) + + static FIELDS: &'static [&'static str] = ["inner"]; + + let mut inner = None; + + loop { + let idx = match try!(d.expect_struct_field_or_end(FIELDS)) { + Some(idx) => idx, + None => { break; } + }; + + match idx { + Some(0) => { inner = Some(try!(d.expect_struct_value())); } + Some(_) => unreachable!(), + None => { let _: IgnoreTokens = try!(Deserializable::deserialize(d)); } + } + } + + Ok(Outer { inner: inner.unwrap() }) } } @@ -1094,7 +1132,6 @@ mod tests { SyntaxError(Vec), UnexpectedName, ConversionError, - IncompleteValue, MissingField(&'static str), } diff --git a/src/json/mod.rs b/src/json/mod.rs index c6750cd8..82a8b615 100644 --- a/src/json/mod.rs +++ b/src/json/mod.rs @@ -742,6 +742,14 @@ impl de::Deserializer for JsonDeserializer { None => Err(UnknownVariantError(variant)), } } + + #[inline] + fn expect_struct_start(&mut self, token: de::Token, _name: &str) -> Result<(), ParserError> { + match token { + de::MapStart(_) => Ok(()), + _ => Err(self.syntax_error(token, [de::MapStartKind])), + } + } } /// The failed expectation of InvalidSyntax @@ -1644,6 +1652,7 @@ pub struct Parser { col: uint, // A state machine is kept to make it possible to interupt and resume parsing. state_stack: Vec, + buf: string::String, } impl> Iterator> for Parser { @@ -1669,8 +1678,20 @@ impl> Iterator> for Parser Some(self.parse_value()), ParseListStart => Some(self.parse_list_start()), ParseListCommaOrEnd => Some(self.parse_list_comma_or_end()), - ParseObjectStart => Some(self.parse_object_start()), - ParseObjectCommaOrEnd => Some(self.parse_object_comma_or_end()), + ParseObjectStart => { + match self.parse_object_start() { + Ok(Some(s)) => Some(Ok(de::String(s.to_string()))), + Ok(None) => Some(Ok(de::End)), + Err(err) => Some(Err(err)), + } + } + ParseObjectCommaOrEnd => { + match self.parse_object_comma_or_end() { + Ok(Some(s)) => Some(Ok(de::String(s.to_string()))), + Ok(None) => Some(Ok(de::End)), + Err(err) => Some(Err(err)), + } + } //ParseObjectKey => Some(self.parse_object_key()), ParseObjectValue => Some(self.parse_object_value()), } @@ -1679,6 +1700,7 @@ impl> Iterator> for Parser> Parser { /// Creates the JSON parser. + #[inline] pub fn new(rdr: Iter) -> Parser { let mut p = Parser { rdr: rdr, @@ -1686,6 +1708,7 @@ impl> Parser { line: 1, col: 0, state_stack: vec!(ParseValue), + buf: string::String::with_capacity(100), }; p.bump(); return p; @@ -1782,6 +1805,7 @@ impl> Parser { Ok(res) } + #[inline] fn parse_decimal(&mut self, res: f64) -> Result { self.bump(); @@ -1874,64 +1898,72 @@ impl> Parser { Ok(n) } - fn parse_string(&mut self) -> Result { + fn parse_string(&mut self) -> Result<&str, ParserError> { + self.buf.clear(); + let mut escape = false; - let mut res = string::String::new(); + loop { - self.bump(); - if self.eof() { - return self.error(EOFWhileParsingString); - } + let ch = match self.next_char() { + Some(ch) => ch, + None => { return self.error(EOFWhileParsingString); } + }; if escape { - match self.ch_or_null() { - '"' => res.push('"'), - '\\' => res.push('\\'), - '/' => res.push('/'), - 'b' => res.push('\x08'), - 'f' => res.push('\x0c'), - 'n' => res.push('\n'), - 'r' => res.push('\r'), - 't' => res.push('\t'), - 'u' => match try!(self.decode_hex_escape()) { - 0xDC00 ... 0xDFFF => return self.error(LoneLeadingSurrogateInHexEscape), + match ch { + '"' => self.buf.push('"'), + '\\' => self.buf.push('\\'), + '/' => self.buf.push('/'), + 'b' => self.buf.push('\x08'), + 'f' => self.buf.push('\x0c'), + 'n' => self.buf.push('\n'), + 'r' => self.buf.push('\r'), + 't' => self.buf.push('\t'), + 'u' => { + let c = match try!(self.decode_hex_escape()) { + 0xDC00 ... 0xDFFF => return self.error(LoneLeadingSurrogateInHexEscape), - // Non-BMP characters are encoded as a sequence of - // two hex escapes, representing UTF-16 surrogates. - n1 @ 0xD800 ... 0xDBFF => { - let c1 = self.next_char(); - let c2 = self.next_char(); - match (c1, c2) { - (Some('\\'), Some('u')) => (), - _ => return self.error(UnexpectedEndOfHexEscape), + // Non-BMP characters are encoded as a sequence of + // two hex escapes, representing UTF-16 surrogates. + n1 @ 0xD800 ... 0xDBFF => { + let c1 = self.next_char(); + let c2 = self.next_char(); + match (c1, c2) { + (Some('\\'), Some('u')) => (), + _ => return self.error(UnexpectedEndOfHexEscape), + } + + let buf = [n1, try!(self.decode_hex_escape())]; + match str::utf16_items(buf.as_slice()).next() { + Some(ScalarValue(c)) => c, + _ => return self.error(LoneLeadingSurrogateInHexEscape), + } } - let buf = [n1, try!(self.decode_hex_escape())]; - match str::utf16_items(buf.as_slice()).next() { - Some(ScalarValue(c)) => res.push(c), - _ => return self.error(LoneLeadingSurrogateInHexEscape), + n => match char::from_u32(n as u32) { + Some(c) => c, + None => return self.error(InvalidUnicodeCodePoint), } - } + }; - n => match char::from_u32(n as u32) { - Some(c) => res.push(c), - None => return self.error(InvalidUnicodeCodePoint), - }, - }, + self.buf.push(c); + } _ => return self.error(InvalidEscape), } escape = false; - } else if self.ch_is('\\') { - escape = true; } else { - match self.ch { - Some('"') => { + match ch { + '"' => { self.bump(); - return Ok(res); - }, - Some(c) => res.push(c), - None => unreachable!() + return Ok(self.buf.as_slice()); + } + '\\' => { + escape = true; + } + ch => { + self.buf.push(ch); + } } } } @@ -1966,26 +1998,26 @@ impl> Parser { } } - fn parse_object_start(&mut self) -> Result { + fn parse_object_start(&mut self) -> Result, ParserError> { self.parse_whitespace(); if self.ch_is('}') { self.bump(); - Ok(de::End) + Ok(None) } else { - self.parse_object_key() + Ok(Some(try!(self.parse_object_key()))) } } - fn parse_object_comma_or_end(&mut self) -> Result { + fn parse_object_comma_or_end(&mut self) -> Result, ParserError> { self.parse_whitespace(); if self.ch_is(',') { self.bump(); - self.parse_object_key() + Ok(Some(try!(self.parse_object_key()))) } else if self.ch_is('}') { self.bump(); - Ok(de::End) + Ok(None) } else if self.eof() { self.error_event(EOFWhileParsingObject) } else { @@ -1993,19 +2025,18 @@ impl> Parser { } } - fn parse_object_key(&mut self) -> Result { + fn parse_object_key(&mut self) -> Result<&str, ParserError> { self.parse_whitespace(); - self.state_stack.push(ParseObjectValue); - if self.eof() { return self.error_event(EOFWhileParsingString); } match self.ch_or_null() { '"' => { - let s = try!(self.parse_string()); - Ok(de::String(s)) + self.state_stack.push(ParseObjectValue); + + Ok(try!(self.parse_string())) } _ => self.error_event(KeyMustBeAString), } @@ -2038,8 +2069,7 @@ impl> Parser { 'f' => self.parse_ident("alse", de::Bool(false)), '0' ... '9' | '-' => self.parse_number(), '"' => { - let s = try!(self.parse_string()); - Ok(de::String(s)) + Ok(de::String(try!(self.parse_string()).to_string())) } '[' => { self.bump(); @@ -2066,7 +2096,7 @@ impl> Parser { } } - fn error_event(&mut self, reason: ErrorCode) -> Result { + fn error_event(&mut self, reason: ErrorCode) -> Result { self.state_stack.clear(); Err(SyntaxError(reason, self.line, self.col)) } @@ -2153,6 +2183,36 @@ impl> de::Deserializer for Parser { _ => self.error(InvalidSyntax(EnumEnd)), } } + + #[inline] + fn expect_struct_start(&mut self, token: de::Token, _name: &str) -> Result<(), ParserError> { + match token { + de::MapStart(_) => Ok(()), + _ => Err(self.syntax_error(token, [de::MapStartKind])), + } + } + + #[inline] + fn expect_struct_field_or_end(&mut self, + fields: &'static [&'static str] + ) -> Result>, ParserError> { + let result = match self.state_stack.pop() { + Some(ParseObjectStart) => { + try!(self.parse_object_start()) + } + Some(ParseObjectCommaOrEnd) => { + try!(self.parse_object_comma_or_end()) + } + _ => fail!("invalid internal state"), + }; + + let s = match result { + Some(s) => s, + None => { return Ok(None); } + }; + + Ok(Some(fields.iter().position(|field| **field == s.as_slice()))) + } } /// Decodes a json value from an `Iterator`.