fix nested arrays with serde

This commit is contained in:
Robin Appelman 2025-08-17 16:19:47 +02:00
commit 0127eecad2
5 changed files with 230 additions and 47 deletions

View file

@ -49,6 +49,15 @@ pub enum Token {
Error,
}
impl Token {
pub(crate) fn is_valid_array_key(&self) -> bool {
matches!(
self,
Token::Integer | Token::LiteralString | Token::Bool | Token::Float | Token::Null
)
}
}
#[test]
fn test_lex() {
let source = r###"

View file

@ -91,7 +91,7 @@ impl<'de> Deserializer<'de> {
}
fn push_peeked(&mut self, peeked: SpannedToken<'de>) {
self.peeked.push_back(peeked)
self.peeked.push_front(peeked)
}
fn parse_unsigned<T>(&mut self) -> Result<T>
@ -500,6 +500,7 @@ impl<'de> SeqAccess<'de> for ArrayWalker<'de, '_> {
where
T: DeserializeSeed<'de>,
{
let source = self.source();
if self.done {
return Ok(None);
}
@ -515,7 +516,7 @@ impl<'de> SeqAccess<'de> for ArrayWalker<'de, '_> {
Token::SquareOpen,
self.syntax.close_bracket(),
],
self.source(),
source,
)?;
if token.token == self.syntax.close_bracket() {
@ -523,31 +524,28 @@ impl<'de> SeqAccess<'de> for ArrayWalker<'de, '_> {
return Ok(None);
}
let next = self.de.next_token().expect_token(
&[self.syntax.close_bracket(), Token::Comma, Token::Arrow],
self.source(),
)?;
let value_token = if token.token.is_valid_array_key() {
let next = self.de.peek_token();
let value_token = match next.token {
Token::Comma => token,
Token::Arrow => {
let span = token.span.clone();
if next.map(|t| t.token) == Some(Token::Arrow) {
self.de.eat_token();
let key_span = token.span.clone();
let key = self.de.parser.parse_array_key(token)?;
match key {
Key::Int(key) if key == self.next_int_key => Ok(()),
Key::Int(_) => Err(ParseError::UnexpectedArrayKey(ArrayKeyError::new(
ArrayKeyErrorKind::NonConsecutive,
self.source(),
span,
key_span,
))),
_ => Err(ParseError::UnexpectedArrayKey(ArrayKeyError::new(
ArrayKeyErrorKind::IntegerExpected,
self.source(),
span,
key_span,
))),
}?;
self.next_int_key += 1;
let value = self.de.next_token().expect_token(
self.de.next_token().expect_token(
&[
Token::Bool,
Token::Integer,
@ -558,26 +556,27 @@ impl<'de> SeqAccess<'de> for ArrayWalker<'de, '_> {
Token::SquareOpen,
],
self.source(),
)?;
let next = self
.de
.next_token()
.expect_token(&[Token::Comma, self.syntax.close_bracket()], self.source())?;
if next.token == self.syntax.close_bracket() {
self.done = true;
}
value
}
peeked_token if peeked_token == self.syntax.close_bracket() => {
self.done = true;
)?
} else {
token
}
_ => unreachable!(),
} else {
token
};
// Deserialize an array element.
self.de.push_peeked(value_token);
seed.deserialize(&mut *self.de).map(Some)
let result = seed.deserialize(&mut *self.de).map(Some)?;
let comma_or_end = self
.de
.next_token()
.expect_token(&[Token::Comma, self.syntax.close_bracket()], source)?;
if comma_or_end.token == self.syntax.close_bracket() {
self.done = true;
}
Ok(result)
}
}
@ -646,8 +645,8 @@ impl<'de> MapAccess<'de> for ArrayWalker<'de, '_> {
// implicit key
let key = self.next_int_key;
self.next_int_key += 1;
self.de.push_peeked(token);
self.de.push_peeked(next);
self.de.push_peeked(token);
seed.deserialize(format!("{}", key).into_deserializer())
.map(Some)
}