fix sequence at end of group, support bare sequences

This commit is contained in:
Robin Appelman 2025-02-28 23:52:55 +01:00
commit fe7bc149d6
10 changed files with 110 additions and 22 deletions

6
flake.lock generated
View file

@ -44,11 +44,11 @@
"rust-overlay": "rust-overlay" "rust-overlay": "rust-overlay"
}, },
"locked": { "locked": {
"lastModified": 1740345481, "lastModified": 1740783063,
"narHash": "sha256-1lAgc6UhpYTHwKm88BUNSnC9nlT4a00rc6UmaE2n0LY=", "narHash": "sha256-nJ/tvNBWFNJtwtNG/KsqtVq4p3aitkEb1pRW0qHvmsk=",
"owner": "icewind1991", "owner": "icewind1991",
"repo": "mill-scale", "repo": "mill-scale",
"rev": "582f15f238322a7f9c129aa5adef12dde3f0a5ce", "rev": "591ea924cfd3cd7932b385341fb0aad0a935bb46",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -122,6 +122,20 @@ impl Entry {
_ => None, _ => None,
} }
} }
pub fn parse<'a, T: Deserialize<'a>>(&'a self) -> Result<T, ParseEntryError> {
let str = self
.as_str()
.ok_or_else(|| ParseEntryError::new(type_name::<T>(), self.clone()))?;
let mut deserializer = crate::serde::Deserializer::from_str(str);
let result = T::deserialize(&mut deserializer)
.map_err(|_| ParseEntryError::new(type_name::<T>(), self.clone()))?;
if deserializer.next().is_some() {
Err(ParseEntryError::new(type_name::<T>(), self.clone()))
} else {
Ok(result)
}
}
} }
/// Parsable types. /// Parsable types.
@ -771,6 +785,21 @@ fn test_serde_entry() {
); );
} }
#[test]
fn test_parse_entry() {
assert_eq!(1, Entry::Value("1".into()).parse::<usize>().unwrap());
assert_eq!(
vec!(1, 2, 3),
Entry::Value("1 2 3".into()).parse::<Vec<u8>>().unwrap()
);
assert_eq!(
(1, 2, 3),
Entry::Value("1 2 3".into())
.parse::<(u8, u8, u8)>()
.unwrap()
);
}
pub(crate) fn string_is_array(string: &str) -> bool { pub(crate) fn string_is_array(string: &str) -> bool {
(string.starts_with('[') && string.ends_with(']')) (string.starts_with('[') && string.ends_with(']'))
|| (string.starts_with('{') && string.ends_with('}')) || (string.starts_with('{') && string.ends_with('}'))

View file

@ -484,7 +484,7 @@ impl<'source, 'a> TableWalker<'source, 'a> {
self.de.source() self.de.source()
} }
fn key_token(&mut self) -> Result<Option<SpannedToken>> { fn key_token(&mut self, retain_group_end: bool) -> Result<Option<SpannedToken>> {
if self.done { if self.done {
return Ok(None); return Ok(None);
} }
@ -512,6 +512,9 @@ impl<'source, 'a> TableWalker<'source, 'a> {
if key.token == Token::GroupEnd { if key.token == Token::GroupEnd {
self.done = true; self.done = true;
if retain_group_end {
self.de.push_peeked(key);
}
return Ok(None); return Ok(None);
} }
Ok(Some(key)) Ok(Some(key))
@ -525,7 +528,7 @@ impl<'de> MapAccess<'de> for TableWalker<'de, '_> {
where where
K: DeserializeSeed<'de>, K: DeserializeSeed<'de>,
{ {
let key = match self.key_token() { let key = match self.key_token(false) {
Ok(Some(key)) => key, Ok(Some(key)) => key,
Ok(None) => { Ok(None) => {
return Ok(None); return Ok(None);
@ -585,20 +588,37 @@ impl<'de> SeqAccess<'de> for SeqWalker<'de, '_> {
if self.done { if self.done {
return Ok(None); return Ok(None);
} }
let value = seed.deserialize(&mut *self.table.de).map(Some)?;
let key_token = match self.table.key_token() { let value = match seed.deserialize(&mut *self.table.de) {
Ok(Some(key)) => key, Ok(value) => Some(value),
Ok(None) => { Err(VdfError::NoValidToken(_)) => None,
return Ok(None);
}
Err(e) => return Err(e), Err(e) => return Err(e),
}; };
let key = key_token.string(self.source()); let value_span = self.table.de.last_span.clone();
if key != self.key { let newline = match self.table.de.peek_span() {
self.table.de.push_peeked(key_token); Some(next_span) => {
self.done = true; let whitespace = &self.source()[value_span.end..next_span.start];
whitespace.contains('\n')
}
_ => false,
};
if newline {
let key_token = match self.table.key_token(true) {
Ok(Some(key)) => key,
Ok(None) => {
self.done = true;
return Ok(value);
}
Err(e) => return Err(e),
};
let key = key_token.string(self.source());
if key != self.key {
self.table.de.push_peeked(key_token);
self.done = true;
}
} }
Ok(value) Ok(value)
@ -866,4 +886,25 @@ mod tests {
let j = r#"1.1"#; let j = r#"1.1"#;
assert_eq!(E::Float(1.1), unwrap_err(from_str(j))); assert_eq!(E::Float(1.1), unwrap_err(from_str(j)));
} }
#[test]
fn test_list_in_struct() {
#[derive(Deserialize, PartialEq, Debug)]
struct Test {
seq: Vec<u8>,
}
let j = r#"{
seq 1
seq 2
seq 3
}"#;
let expected = Test { seq: vec![1, 2, 3] };
assert_eq!(expected, unwrap_err(from_str(j)));
let j = r#"{
seq 1 2 3
}"#;
assert_eq!(expected, unwrap_err(from_str(j)));
}
} }

View file

@ -8,6 +8,6 @@
array "3" array "3"
windows_path "C:\test\no newline" windows_path "C:\test\no newline"
\\"$translucent" 1 // this is read vdf written by real valve developers \\"$translucent" 1 // this is real vdf written by real valve developers
"$envmaptint" .5 .5 .5 // found in the wild, pretty sure they mean "[.5 .5 .5]", but it ends up working by accident with a stray `.5 = .5` kv "$envmaptint" .5 .5 .5
} }

View file

@ -5,4 +5,5 @@
single 1.2 single 1.2
triple "{1.2 1.3 1.4}" triple "{1.2 1.3 1.4}"
single_int 2 single_int 2
another_tuple 8 foo 0
} }

View file

@ -18,6 +18,7 @@ enum Expected {
single: SingleOrTriple<f32>, single: SingleOrTriple<f32>,
triple: SingleOrTriple<f32>, triple: SingleOrTriple<f32>,
single_int: SingleOrTriple<f32>, single_int: SingleOrTriple<f32>,
another_tuple: (u8, String, bool),
}, },
LightmappedGeneric { LightmappedGeneric {
#[serde(rename = "$baseTexture")] #[serde(rename = "$baseTexture")]
@ -45,9 +46,7 @@ enum Expected {
#[serde(rename = r#"\\"$translucent""#)] #[serde(rename = r#"\\"$translucent""#)]
translucent: bool, translucent: bool,
#[serde(rename = "$envmaptint")] #[serde(rename = "$envmaptint")]
env_map_tint: f32, env_map_tint: [f32; 3],
#[serde(rename = ".5")]
spare: f32,
}, },
UserConfigData { UserConfigData {
#[serde(rename = "Steam")] #[serde(rename = "Steam")]

View file

@ -4,6 +4,7 @@ expression: result
--- ---
{ {
"Types": { "Types": {
"another_tuple": "8",
"fixed_array": [ "fixed_array": [
"1", "1",
"2", "2",
@ -13,6 +14,7 @@ expression: result
"1", "1",
"2.2", "2.2",
], ],
"foo": "0",
"single": "1.2", "single": "1.2",
"single_int": "2", "single_int": "2",
"triple": [ "triple": [

View file

@ -0,0 +1,16 @@
---
source: tests/serde.rs
expression: out
---
vmt_reader::unexpected_token
× invalid type: boolean `true`, expected u32
╭─[6:9]
5 │ }
6 │ ╭─▶ data2 {
7 │ │ kind Bar
8 │ │ val1 1
9 │ ├─▶ }
· ╰──── invalid type: boolean `true`, expected u32
10 │ }
╰────

View file

@ -11,6 +11,5 @@ r#Resource/specificPanel.res(
], ],
windows_path: "C:\\test\\no newline", windows_path: "C:\\test\\no newline",
r#\\"$translucent": true, r#\\"$translucent": true,
r#$envmaptint: 0.5, r#$envmaptint: (0.5, 0.5, 0.5),
r#.5: 0.5,
) )

View file

@ -12,4 +12,5 @@ Types(
single: 1.2, single: 1.2,
triple: (1.2, 1.3, 1.4), triple: (1.2, 1.3, 1.4),
single_int: 2.0, single_int: 2.0,
another_tuple: (8, "foo", false),
) )