mirror of
https://codeberg.org/icewind/vdf-reader.git
synced 2026-06-03 10:04:08 +02:00
fix sequence at end of group, support bare sequences
This commit is contained in:
parent
eeeb47560b
commit
fe7bc149d6
10 changed files with 110 additions and 22 deletions
6
flake.lock
generated
6
flake.lock
generated
|
|
@ -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": {
|
||||||
|
|
|
||||||
|
|
@ -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('}'))
|
||||||
|
|
|
||||||
65
src/serde.rs
65
src/serde.rs
|
|
@ -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)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
@ -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")]
|
||||||
|
|
|
||||||
|
|
@ -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": [
|
||||||
|
|
|
||||||
16
tests/snapshots/serde__tests__data__internal_tag.vdf.snap
Normal file
16
tests/snapshots/serde__tests__data__internal_tag.vdf.snap
Normal 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 │ }
|
||||||
|
╰────
|
||||||
|
|
@ -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,
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue