serde: allow top level map

This commit is contained in:
Robin Appelman 2023-12-18 15:04:16 +01:00
commit 85ad728ac8
2 changed files with 76 additions and 16 deletions

View file

@ -321,10 +321,27 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
self.next() // as a special case we allow a map without a `{` at the start of the file to create a top level struct
.expect_token(&[Token::GroupStart], self.source())?; let toplevel = match dbg!(self
.peek()
.expect_token(&[Token::GroupStart], self.source()))
{
Ok(_) => {
let _ = self.next();
false
}
Err(VdfError::UnexpectedToken(e)) => {
if dbg!(self.tokenizer.count) > 1 {
return Err(e.into());
}
true
}
Err(e) => {
return Err(e);
}
};
let value = visitor.visit_map(TableWalker::new(&mut self))?; let value = visitor.visit_map(TableWalker::new(&mut self, toplevel))?;
Ok(value) Ok(value)
} }
@ -370,11 +387,24 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
struct TableWalker<'source, 'a> { struct TableWalker<'source, 'a> {
de: &'a mut Deserializer<'source>, de: &'a mut Deserializer<'source>,
done: bool, done: bool,
toplevel: bool,
} }
const KEY_TOKEN: &[Token] = &[
Token::Item,
Token::QuotedItem,
Token::Statement,
Token::QuotedStatement,
Token::GroupEnd,
];
impl<'source, 'a> TableWalker<'source, 'a> { impl<'source, 'a> TableWalker<'source, 'a> {
pub fn new(de: &'a mut Deserializer<'source>) -> Self { pub fn new(de: &'a mut Deserializer<'source>, toplevel: bool) -> Self {
TableWalker { de, done: false } TableWalker {
de,
done: false,
toplevel,
}
} }
fn source(&self) -> &'source str { fn source(&self) -> &'source str {
@ -386,16 +416,26 @@ impl<'source, 'a> TableWalker<'source, 'a> {
return Ok(None); return Ok(None);
} }
let key = self.de.next().expect_token( let expected = if self.toplevel {
&[ STRING_ITEMS
Token::Item, } else {
Token::QuotedItem, KEY_TOKEN
Token::Statement, };
Token::QuotedStatement,
Token::GroupEnd, let token = match (self.de.next(), self.toplevel) {
], (Some(token), _) => token,
self.source(), (None, true) => {
)?; self.done = true;
return Ok(None);
}
(None, false) => {
return Err(None::<SpannedToken>
.expect_token(expected, self.source())
.unwrap_err())
}
};
let key = token.expect_token(expected, self.source())?;
if key.token == Token::GroupEnd { if key.token == Token::GroupEnd {
self.done = true; self.done = true;
@ -444,7 +484,7 @@ impl<'source, 'a> SeqWalker<'source, 'a> {
SeqWalker { SeqWalker {
done: false, done: false,
key, key,
table: TableWalker::new(de), table: TableWalker::new(de, false),
} }
} }
@ -595,6 +635,22 @@ mod tests {
assert_eq!(expected, unwrap_err(from_str(j))); assert_eq!(expected, unwrap_err(from_str(j)));
} }
#[test]
fn test_struct_toplevel() {
#[derive(Deserialize, PartialEq, Debug)]
struct Test {
int: u32,
seq: String,
}
let j = r#""int" 1 "seq" "b""#;
let expected = Test {
int: 1,
seq: "b".into(),
};
assert_eq!(expected, unwrap_err(from_str(j)));
}
#[test] #[test]
fn test_struct_nested() { fn test_struct_nested() {
#[derive(Deserialize, PartialEq, Debug)] #[derive(Deserialize, PartialEq, Debug)]

View file

@ -21,12 +21,15 @@ impl SpannedToken {
pub struct Tokenizer<'source> { pub struct Tokenizer<'source> {
lexer: Lexer<'source, Token>, lexer: Lexer<'source, Token>,
/// The number of tokens tokenized so far
pub count: usize,
} }
impl<'source> Tokenizer<'source> { impl<'source> Tokenizer<'source> {
pub fn from_str(input: &'source str) -> Self { pub fn from_str(input: &'source str) -> Self {
Tokenizer { Tokenizer {
lexer: Lexer::new(input), lexer: Lexer::new(input),
count: 0,
} }
} }
@ -48,6 +51,7 @@ impl<'source> Iterator for Tokenizer<'source> {
return None; return None;
} }
}; };
self.count += 1;
Some(Ok(SpannedToken { Some(Ok(SpannedToken {
token, token,
span: self.lexer.span(), span: self.lexer.span(),