mirror of
https://codeberg.org/icewind/vdf-reader.git
synced 2026-06-03 18:14:07 +02:00
serde: allow top level map
This commit is contained in:
parent
f75a64204c
commit
85ad728ac8
2 changed files with 76 additions and 16 deletions
88
src/serde.rs
88
src/serde.rs
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue