boxed arrays

This commit is contained in:
Robin Appelman 2023-12-18 16:36:14 +01:00
commit d54e44b51d
7 changed files with 143 additions and 6 deletions

View file

@ -42,6 +42,42 @@ pub enum VdfError {
Other(String), Other(String),
} }
impl VdfError {
pub(crate) fn with_source_span<Sp: Into<SourceSpan>, Sr: Into<String>>(
self,
span: Sp,
source: Sr,
) -> VdfError {
match self {
VdfError::UnexpectedToken(e) => UnexpectedTokenError {
src: source.into(),
err_span: span.into(),
..e
}
.into(),
VdfError::NoValidToken(e) => NoValidTokenError {
src: source.into(),
err_span: span.into(),
..e
}
.into(),
VdfError::WrongEntryType(e) => WrongEventTypeError {
src: source.into(),
err_span: span.into(),
..e
}
.into(),
VdfError::SerdeParse(e) => SerdeParseError {
src: source.into(),
err_span: span.into(),
..e
}
.into(),
_ => self,
}
}
}
struct ExpectedTokens<'a>(&'a [Token]); struct ExpectedTokens<'a>(&'a [Token]);
impl Display for ExpectedTokens<'_> { impl Display for ExpectedTokens<'_> {

View file

@ -293,9 +293,17 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
let key = self.last_key.clone(); let token = self.peek().expect_token(STRING_ITEMS, self.source())?;
let value = visitor.visit_seq(SeqWalker::new(&mut self, key))?; let value_str = &self.source()[token.span.clone()];
Ok(value) if value_str.starts_with("\"[") && value_str.ends_with("]\"") {
let _ = self.next();
let seq = &value_str[2..value_str.len() - 2];
let span = token.span.start + 2..token.span.end - 2;
visitor.visit_seq(StringArrayWalker::new(self.source(), seq, span))
} else {
let key = self.last_key.clone();
visitor.visit_seq(SeqWalker::new(&mut self, key))
}
} }
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value> fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
@ -322,16 +330,16 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
V: Visitor<'de>, V: Visitor<'de>,
{ {
// as a special case we allow a map without a `{` at the start of the file to create a top level struct // as a special case we allow a map without a `{` at the start of the file to create a top level struct
let toplevel = match dbg!(self let toplevel = match self
.peek() .peek()
.expect_token(&[Token::GroupStart], self.source())) .expect_token(&[Token::GroupStart], self.source())
{ {
Ok(_) => { Ok(_) => {
let _ = self.next(); let _ = self.next();
false false
} }
Err(VdfError::UnexpectedToken(e)) => { Err(VdfError::UnexpectedToken(e)) => {
if dbg!(self.tokenizer.count) > 1 { if self.tokenizer.count > 1 {
return Err(e.into()); return Err(e.into());
} }
true true
@ -526,6 +534,55 @@ impl<'de, 'a> SeqAccess<'de> for SeqWalker<'de, 'a> {
} }
} }
struct StringArrayWalker<'source> {
source: &'source str,
remaining: &'source str,
span: Span,
}
impl<'source> StringArrayWalker<'source> {
fn new(source: &'source str, array: &'source str, span: Span) -> Self {
StringArrayWalker {
source,
remaining: array,
span,
}
}
}
impl<'de, 'source> SeqAccess<'de> for StringArrayWalker<'source>
where
'source: 'de,
{
type Error = VdfError;
fn next_element_seed<T>(
&mut self,
seed: T,
) -> std::result::Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
if self.remaining.is_empty() {
return Ok(None);
}
let (item, rest) = self
.remaining
.split_once(" ")
.unwrap_or((self.remaining, ""));
let item_span = self.span.start..(self.span.start + item.len());
self.remaining = rest.trim();
self.span = (self.span.end - self.remaining.len())..self.span.end;
let mut de = Deserializer::from_str(item);
let val = seed
.deserialize(&mut de)
.map_err(|e| e.with_source_span(item_span, self.source))?;
Ok(Some(val))
}
}
struct Enum<'a, 'de: 'a> { struct Enum<'a, 'de: 'a> {
de: &'a mut Deserializer<'de>, de: &'a mut Deserializer<'de>,
} }

View file

@ -0,0 +1,5 @@
"Types" {
fixed_array "[1 2 3]"
flex_array "[1.0 2.2]"
tuple "[1 57]"
}

View file

@ -0,0 +1,5 @@
"Types" {
fixed_array "[1 2 3.1]"
flex_array "[1.0 2.2]"
tuple "[1 57]"
}

View file

@ -7,6 +7,11 @@ use vdf_reader::from_str;
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
enum Expected { enum Expected {
Types {
fixed_array: [u8; 3],
flex_array: Vec<f32>,
tuple: (bool, u8),
},
LightmappedGeneric { LightmappedGeneric {
#[serde(rename = "$baseTexture")] #[serde(rename = "$baseTexture")]
base_texture: String, base_texture: String,
@ -152,8 +157,10 @@ struct GameList {
#[test_case("tests/data/concrete.vmt")] #[test_case("tests/data/concrete.vmt")]
#[test_case("tests/data/messy.vdf")] #[test_case("tests/data/messy.vdf")]
#[test_case("tests/data/DialogConfigOverlay_1280x720.vdf")] #[test_case("tests/data/DialogConfigOverlay_1280x720.vdf")]
#[test_case("tests/data/serde_array_type.vdf")]
#[test_case("tests/errors/concrete.vmt")] #[test_case("tests/errors/concrete.vmt")]
#[test_case("tests/errors/novalue.vdf")] #[test_case("tests/errors/novalue.vdf")]
#[test_case("tests/errors/serde_array_type.vdf")]
fn test_serde(path: &str) { fn test_serde(path: &str) {
let raw = read_to_string(path).unwrap(); let raw = read_to_string(path).unwrap();
match from_str::<Expected>(&raw) { match from_str::<Expected>(&raw) {

View file

@ -0,0 +1,12 @@
---
source: tests/serde.rs
expression: result
---
Types(
fixed_array: (1, 2, 3),
flex_array: [
1.0,
2.2,
],
tuple: (true, 57),
)

View file

@ -0,0 +1,15 @@
---
source: tests/serde.rs
expression: out
---
vmt_parser::parse_serde
× Can't parse "3.1" as u8
╭─[1:1]
1 │ "Types" {
2 │ fixed_array "[1 2 3.1]"
· ─┬─
· ╰── Expected a u8
3 │ flex_array "[1.0 2.2]"
╰────