mirror of
https://codeberg.org/icewind/vdf-reader.git
synced 2026-06-04 02:24:08 +02:00
add support for deserializing a map with int keys as a sequence
This commit is contained in:
parent
1a37f7e866
commit
b928f85df6
14 changed files with 226 additions and 9 deletions
|
|
@ -1,5 +1,6 @@
|
|||
use super::Entry;
|
||||
use super::{Entry, Table};
|
||||
use crate::entry::Value;
|
||||
use crate::error::{ParseStringError, UnknownError};
|
||||
use crate::VdfError;
|
||||
use serde::de::{DeserializeSeed, SeqAccess};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -80,3 +81,53 @@ impl<'de> SeqAccess<'de> for ArraySeq {
|
|||
seed.deserialize(next).map(Some)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TableArraySeq {
|
||||
iter: std::vec::IntoIter<(String, Entry)>,
|
||||
last_key: Option<u64>,
|
||||
}
|
||||
|
||||
impl TableArraySeq {
|
||||
pub(crate) fn new(table: Table) -> Self {
|
||||
// since the tables map doesn't have a stable order, we need to re-sort them to have the keys in order
|
||||
let mut items: Vec<_> = table.into_iter().collect();
|
||||
items.sort_by(|(key_a, _), (key_b, _)| key_a.cmp(key_b));
|
||||
TableArraySeq {
|
||||
iter: items.into_iter(),
|
||||
last_key: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> SeqAccess<'de> for TableArraySeq {
|
||||
type Error = VdfError;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: DeserializeSeed<'de>,
|
||||
{
|
||||
let (key, next) = match self.iter.next() {
|
||||
Some(next) => next,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let key: u64 = key.parse().map_err(|_| {
|
||||
VdfError::ParseString(ParseStringError {
|
||||
ty: "u64",
|
||||
value: key,
|
||||
})
|
||||
})?;
|
||||
|
||||
if let Some(last_key) = self.last_key {
|
||||
let expected_key = last_key + 1;
|
||||
if expected_key != key {
|
||||
return Err(VdfError::Other(UnknownError::from(format!(
|
||||
"Invalid array key {key}, expected {expected_key}"
|
||||
))));
|
||||
}
|
||||
}
|
||||
self.last_key = Some(key);
|
||||
|
||||
seed.deserialize(next).map(Some)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ macro_rules! from_str {
|
|||
);
|
||||
}
|
||||
|
||||
use crate::entry::array::ArraySeq;
|
||||
use crate::entry::array::{ArraySeq, TableArraySeq};
|
||||
use crate::entry::table::TableSeq;
|
||||
use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
|
|
@ -614,7 +614,8 @@ impl<'de> Deserializer<'de> for Entry {
|
|||
{
|
||||
match self {
|
||||
Entry::Array(arr) => visitor.visit_seq(ArraySeq::new(arr)),
|
||||
_ => Err(UnknownError::from("array2").into()),
|
||||
Entry::Table(table) => visitor.visit_seq(TableArraySeq::new(table)),
|
||||
_ => Err(UnknownError::from("array").into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use std::ops::{Deref, DerefMut};
|
|||
/// A table of entries.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize, Default)]
|
||||
#[serde(transparent)]
|
||||
pub struct Table(#[serde(serialize_with = "ordered_map")] HashMap<String, Entry>);
|
||||
pub struct Table(#[serde(serialize_with = "ordered_map")] HashMap<String, Entry>); // todo: switch to a map that maintains item order
|
||||
|
||||
impl From<HashMap<String, Entry>> for Table {
|
||||
fn from(value: HashMap<String, Entry>) -> Self {
|
||||
|
|
@ -118,6 +118,15 @@ impl Table {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Table {
|
||||
type Item = (String, Entry);
|
||||
type IntoIter = hash_map::IntoIter<String, Entry>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Table> for Entry {
|
||||
fn from(table: Table) -> Self {
|
||||
Entry::Table(table)
|
||||
|
|
|
|||
10
src/error.rs
10
src/error.rs
|
|
@ -181,6 +181,16 @@ impl From<&str> for UnknownError {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<String> for UnknownError {
|
||||
fn from(value: String) -> Self {
|
||||
UnknownError {
|
||||
error: value,
|
||||
err_span: (0..0).into(),
|
||||
src: String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A token that wasn't expected was found while parsing
|
||||
#[derive(Debug, Clone, Diagnostic)]
|
||||
#[diagnostic(code(vmt_reader::unexpected_token))]
|
||||
|
|
|
|||
54
src/serde.rs
54
src/serde.rs
|
|
@ -1,5 +1,5 @@
|
|||
use crate::entry::{string_is_array, Entry, ParseItem};
|
||||
use crate::error::{ExpectToken, NoValidTokenError, ResultExt, SerdeParseError};
|
||||
use crate::error::{ExpectToken, NoValidTokenError, ResultExt, SerdeParseError, UnknownError};
|
||||
use crate::tokenizer::{SpannedToken, Tokenizer};
|
||||
use crate::{Token, VdfError};
|
||||
use logos::Span;
|
||||
|
|
@ -348,7 +348,17 @@ impl<'de> de::Deserializer<'de> for &'_ mut Deserializer<'de> {
|
|||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let token = self.peek().expect_token(STRING_ITEMS, self.source())?;
|
||||
let token = self.peek().expect_token(SEQ_START_ITEMS, self.source())?;
|
||||
|
||||
if token.token == Token::GroupStart {
|
||||
// we allow deserializing a map of consecutive int keys as a seq
|
||||
let _ = self.next();
|
||||
return visitor.visit_seq(MapSeqWalker {
|
||||
table: TableWalker::new(self, false),
|
||||
last_key: None,
|
||||
});
|
||||
}
|
||||
|
||||
let value_str = &self.source()[token.span.clone()];
|
||||
if (value_str.starts_with("\"[") && value_str.ends_with("]\""))
|
||||
|| (value_str.starts_with("\"{") && value_str.ends_with("}\""))
|
||||
|
|
@ -555,6 +565,15 @@ impl<'de> MapAccess<'de> for TableWalker<'de, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// STRING_ITEMS and GroupStart
|
||||
const SEQ_START_ITEMS: &[Token] = &[
|
||||
Token::Item,
|
||||
Token::QuotedItem,
|
||||
Token::Statement,
|
||||
Token::QuotedStatement,
|
||||
Token::GroupStart,
|
||||
];
|
||||
|
||||
struct SeqWalker<'source, 'a> {
|
||||
table: TableWalker<'source, 'a>,
|
||||
key: Cow<'source, str>,
|
||||
|
|
@ -674,6 +693,37 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
struct MapSeqWalker<'source, 'a> {
|
||||
table: TableWalker<'source, 'a>,
|
||||
last_key: Option<u64>,
|
||||
}
|
||||
|
||||
impl<'de> SeqAccess<'de> for MapSeqWalker<'de, '_> {
|
||||
type Error = VdfError;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: DeserializeSeed<'de>,
|
||||
{
|
||||
let Some(key) = self.table.next_key()? else {
|
||||
return Ok(None);
|
||||
};
|
||||
if let Some(last_key) = self.last_key {
|
||||
let expected_key = last_key + 1;
|
||||
if expected_key != key {
|
||||
return Err(VdfError::Other(UnknownError::from(format!(
|
||||
"Invalid array key {key}, expected {expected_key}"
|
||||
)))
|
||||
.with_source_span(self.table.de.last_span.clone(), self.table.de.source()));
|
||||
}
|
||||
}
|
||||
|
||||
self.last_key = Some(key);
|
||||
|
||||
Ok(Some(self.table.next_value_seed(seed)?))
|
||||
}
|
||||
}
|
||||
|
||||
struct Enum<'a, 'de: 'a> {
|
||||
de: &'a mut Deserializer<'de>,
|
||||
enclosed: bool,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue