Skip to content

Commit

Permalink
Split out peek logic from seed generic
Browse files Browse the repository at this point in the history
  • Loading branch information
GnomedDev committed May 30, 2024
1 parent 62839b7 commit 1509d87
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 63 deletions.
99 changes: 45 additions & 54 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ impl ParserNumber {
}
}

enum PeekResult {
Char(u8),
EndOfSeq,
EofSeq,
Eof,
}

impl<'de, R: Read<'de>> Deserializer<R> {
/// 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
Expand Down Expand Up @@ -259,6 +266,28 @@ impl<'de, R: Read<'de>> Deserializer<R> {
}
}

fn peek_next_elem<const END: u8>(&mut self, first: &mut bool) -> Result<PeekResult> {
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') {
Expand Down Expand Up @@ -1163,8 +1192,8 @@ impl<'de, R: Read<'de>> Deserializer<R> {
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 {
Expand Down Expand Up @@ -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<R>) -> Self {
SeqAccess { de, first: true }
}
Expand All @@ -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::<b']'>(&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)),
}
}
}
Expand All @@ -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::<b'}'>(&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)),
}
}

Expand Down
15 changes: 6 additions & 9 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 `\"`"),
Expand Down

0 comments on commit 1509d87

Please sign in to comment.