diff --git a/src/de.rs b/src/de.rs index c7774f687..ff5fa867a 100644 --- a/src/de.rs +++ b/src/de.rs @@ -133,6 +133,13 @@ impl ParserNumber { } } +enum PeekResult { + Char(u8), + EndOfSeq, + EofSeq, + Eof, +} + impl<'de, R: Read<'de>> Deserializer { /// The `Deserializer::end` method should be called after a value has been fully deserialized. /// This allows the `Deserializer` to validate that the input stream is at the end or that it @@ -259,6 +266,28 @@ impl<'de, R: Read<'de>> Deserializer { } } + fn peek_next_elem(&mut self, first: &mut bool) -> Result { + match tri!(self.parse_whitespace()) { + Some(c) if c == END => Ok(PeekResult::EndOfSeq), + Some(b',') if !*first => { + self.eat_char(); + self.parse_whitespace().map(|c| match c { + Some(c) => PeekResult::Char(c), + None => PeekResult::Eof, + }) + } + Some(b) => { + if *first { + *first = false; + Ok(PeekResult::Char(b)) + } else { + Err(self.peek_error(ErrorCode::ExpectedNextOrEnd { end: END })) + } + } + None => Ok(PeekResult::EofSeq), + } + } + #[cold] fn peek_invalid_type(&mut self, exp: &dyn Expected) -> Error { let err = match self.peek_or_null().unwrap_or(b'\x00') { @@ -1163,8 +1192,8 @@ impl<'de, R: Read<'de>> Deserializer { Some(_) => { if accept_comma { return Err(self.peek_error(match frame { - b'[' => ErrorCode::ExpectedListCommaOrEnd, - b'{' => ErrorCode::ExpectedObjectCommaOrEnd, + b'[' => ErrorCode::ExpectedNextOrEnd { end: b']' }, + b'{' => ErrorCode::ExpectedNextOrEnd { end: b'}' }, _ => unreachable!(), })); } else { @@ -1909,7 +1938,7 @@ struct SeqAccess<'a, R: 'a> { first: bool, } -impl<'a, R: 'a> SeqAccess<'a, R> { +impl<'de, 'a, R: Read<'de> + 'a> SeqAccess<'a, R> { fn new(de: &'a mut Deserializer) -> Self { SeqAccess { de, first: true } } @@ -1922,31 +1951,12 @@ impl<'de, 'a, R: Read<'de> + 'a> de::SeqAccess<'de> for SeqAccess<'a, R> { where T: de::DeserializeSeed<'de>, { - let peek = match tri!(self.de.parse_whitespace()) { - Some(b']') => { - return Ok(None); - } - Some(b',') if !self.first => { - self.de.eat_char(); - tri!(self.de.parse_whitespace()) - } - Some(b) => { - if self.first { - self.first = false; - Some(b) - } else { - return Err(self.de.peek_error(ErrorCode::ExpectedListCommaOrEnd)); - } - } - None => { - return Err(self.de.peek_error(ErrorCode::EofWhileParsingList)); - } - }; - - match peek { - Some(b']') => Err(self.de.peek_error(ErrorCode::TrailingComma)), - Some(_) => Ok(Some(tri!(seed.deserialize(&mut *self.de)))), - None => Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)), + match tri!(self.de.peek_next_elem::(&mut self.first)) { + PeekResult::EndOfSeq => Ok(None), + PeekResult::Char(b']') => Err(self.de.peek_error(ErrorCode::TrailingComma)), + PeekResult::Char(_) => Ok(Some(tri!(seed.deserialize(&mut *self.de)))), + PeekResult::Eof => Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)), + PeekResult::EofSeq => Err(self.de.peek_error(ErrorCode::EofWhileParsingList)), } } } @@ -1969,32 +1979,13 @@ impl<'de, 'a, R: Read<'de> + 'a> de::MapAccess<'de> for MapAccess<'a, R> { where K: de::DeserializeSeed<'de>, { - let peek = match tri!(self.de.parse_whitespace()) { - Some(b'}') => { - return Ok(None); - } - Some(b',') if !self.first => { - self.de.eat_char(); - tri!(self.de.parse_whitespace()) - } - Some(b) => { - if self.first { - self.first = false; - Some(b) - } else { - return Err(self.de.peek_error(ErrorCode::ExpectedObjectCommaOrEnd)); - } - } - None => { - return Err(self.de.peek_error(ErrorCode::EofWhileParsingObject)); - } - }; - - match peek { - Some(b'"') => seed.deserialize(MapKey { de: &mut *self.de }).map(Some), - Some(b'}') => Err(self.de.peek_error(ErrorCode::TrailingComma)), - Some(_) => Err(self.de.peek_error(ErrorCode::KeyMustBeAString)), - None => Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)), + match tri!(self.de.peek_next_elem::(&mut self.first)) { + PeekResult::EndOfSeq => Ok(None), + PeekResult::Char(b'"') => seed.deserialize(MapKey { de: &mut *self.de }).map(Some), + PeekResult::Char(b'}') => Err(self.de.peek_error(ErrorCode::TrailingComma)), + PeekResult::Char(_) => Err(self.de.peek_error(ErrorCode::KeyMustBeAString)), + PeekResult::Eof => Err(self.de.peek_error(ErrorCode::EofWhileParsingValue)), + PeekResult::EofSeq => Err(self.de.peek_error(ErrorCode::EofWhileParsingObject)), } } diff --git a/src/error.rs b/src/error.rs index fbf9eb14e..78e48e079 100644 --- a/src/error.rs +++ b/src/error.rs @@ -60,8 +60,7 @@ impl Error { | ErrorCode::EofWhileParsingString | ErrorCode::EofWhileParsingValue => Category::Eof, ErrorCode::ExpectedColon - | ErrorCode::ExpectedListCommaOrEnd - | ErrorCode::ExpectedObjectCommaOrEnd + | ErrorCode::ExpectedNextOrEnd { .. } | ErrorCode::ExpectedSomeIdent | ErrorCode::ExpectedSomeValue | ErrorCode::ExpectedDoubleQuote @@ -255,11 +254,8 @@ pub(crate) enum ErrorCode { /// Expected this character to be a `':'`. ExpectedColon, - /// Expected this character to be either a `','` or a `']'`. - ExpectedListCommaOrEnd, - - /// Expected this character to be either a `','` or a `'}'`. - ExpectedObjectCommaOrEnd, + /// Expected this character to be either ',' or end. + ExpectedNextOrEnd { end: u8 }, /// Expected to parse either a `true`, `false`, or a `null`. ExpectedSomeIdent, @@ -356,8 +352,9 @@ impl Display for ErrorCode { ErrorCode::EofWhileParsingString => f.write_str("EOF while parsing a string"), ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing a value"), ErrorCode::ExpectedColon => f.write_str("expected `:`"), - ErrorCode::ExpectedListCommaOrEnd => f.write_str("expected `,` or `]`"), - ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"), + ErrorCode::ExpectedNextOrEnd { end } => { + write!(f, "expected `,` or `{}`", *end as char) + } ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"), ErrorCode::ExpectedSomeValue => f.write_str("expected value"), ErrorCode::ExpectedDoubleQuote => f.write_str("expected `\"`"),