better array string handling

This commit is contained in:
Robin Appelman 2023-12-19 18:19:41 +01:00
commit d14f22d1bc
6 changed files with 68 additions and 10 deletions

View file

@ -1,4 +1,5 @@
use super::Entry; use super::Entry;
use crate::entry::Value;
use crate::VdfError; use crate::VdfError;
use serde::de::{DeserializeSeed, SeqAccess}; use serde::de::{DeserializeSeed, SeqAccess};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -9,6 +10,18 @@ use std::ops::{Deref, DerefMut};
#[serde(transparent)] #[serde(transparent)]
pub struct Array(Vec<Entry>); pub struct Array(Vec<Entry>);
impl Array {
pub(crate) fn from_space_separated(str: &str) -> Self {
let items = str
.split(' ')
.filter(|part| !part.is_empty())
.map(Value::from)
.map(Entry::from)
.collect();
Array(items)
}
}
impl From<Vec<Entry>> for Array { impl From<Vec<Entry>> for Array {
fn from(value: Vec<Entry>) -> Self { fn from(value: Vec<Entry>) -> Self {
Array(value) Array(value)

View file

@ -353,6 +353,7 @@ impl<'de> Deserializer<'de> for Entry {
{ {
match self { match self {
Entry::Value(val) => val.deserialize_bool(visitor), Entry::Value(val) => val.deserialize_bool(visitor),
Entry::Statement(val) => Value::from(val).deserialize_bool(visitor),
_ => Err(UnknownError::from("bool").into()), _ => Err(UnknownError::from("bool").into()),
} }
} }
@ -363,6 +364,7 @@ impl<'de> Deserializer<'de> for Entry {
{ {
match self { match self {
Entry::Value(val) => val.deserialize_i8(visitor), Entry::Value(val) => val.deserialize_i8(visitor),
Entry::Statement(val) => Value::from(val).deserialize_i8(visitor),
_ => Err(UnknownError::from("i8").into()), _ => Err(UnknownError::from("i8").into()),
} }
} }
@ -373,6 +375,7 @@ impl<'de> Deserializer<'de> for Entry {
{ {
match self { match self {
Entry::Value(val) => val.deserialize_i16(visitor), Entry::Value(val) => val.deserialize_i16(visitor),
Entry::Statement(val) => Value::from(val).deserialize_i16(visitor),
_ => Err(UnknownError::from("i16").into()), _ => Err(UnknownError::from("i16").into()),
} }
} }
@ -383,6 +386,7 @@ impl<'de> Deserializer<'de> for Entry {
{ {
match self { match self {
Entry::Value(val) => val.deserialize_i32(visitor), Entry::Value(val) => val.deserialize_i32(visitor),
Entry::Statement(val) => Value::from(val).deserialize_i32(visitor),
_ => Err(UnknownError::from("i32").into()), _ => Err(UnknownError::from("i32").into()),
} }
} }
@ -393,6 +397,7 @@ impl<'de> Deserializer<'de> for Entry {
{ {
match self { match self {
Entry::Value(val) => val.deserialize_i64(visitor), Entry::Value(val) => val.deserialize_i64(visitor),
Entry::Statement(val) => Value::from(val).deserialize_i64(visitor),
_ => Err(UnknownError::from("i64").into()), _ => Err(UnknownError::from("i64").into()),
} }
} }
@ -403,6 +408,7 @@ impl<'de> Deserializer<'de> for Entry {
{ {
match self { match self {
Entry::Value(val) => val.deserialize_u8(visitor), Entry::Value(val) => val.deserialize_u8(visitor),
Entry::Statement(val) => Value::from(val).deserialize_u8(visitor),
_ => Err(UnknownError::from("u8").into()), _ => Err(UnknownError::from("u8").into()),
} }
} }
@ -413,6 +419,7 @@ impl<'de> Deserializer<'de> for Entry {
{ {
match self { match self {
Entry::Value(val) => val.deserialize_u16(visitor), Entry::Value(val) => val.deserialize_u16(visitor),
Entry::Statement(val) => Value::from(val).deserialize_u16(visitor),
_ => Err(UnknownError::from("u16").into()), _ => Err(UnknownError::from("u16").into()),
} }
} }
@ -423,6 +430,7 @@ impl<'de> Deserializer<'de> for Entry {
{ {
match self { match self {
Entry::Value(val) => val.deserialize_u32(visitor), Entry::Value(val) => val.deserialize_u32(visitor),
Entry::Statement(val) => Value::from(val).deserialize_u32(visitor),
_ => Err(UnknownError::from("u32").into()), _ => Err(UnknownError::from("u32").into()),
} }
} }
@ -433,6 +441,7 @@ impl<'de> Deserializer<'de> for Entry {
{ {
match self { match self {
Entry::Value(val) => val.deserialize_u64(visitor), Entry::Value(val) => val.deserialize_u64(visitor),
Entry::Statement(val) => Value::from(val).deserialize_u64(visitor),
_ => Err(UnknownError::from("u64").into()), _ => Err(UnknownError::from("u64").into()),
} }
} }
@ -443,6 +452,7 @@ impl<'de> Deserializer<'de> for Entry {
{ {
match self { match self {
Entry::Value(val) => val.deserialize_f32(visitor), Entry::Value(val) => val.deserialize_f32(visitor),
Entry::Statement(val) => Value::from(val).deserialize_f32(visitor),
_ => Err(UnknownError::from("f32").into()), _ => Err(UnknownError::from("f32").into()),
} }
} }
@ -453,6 +463,7 @@ impl<'de> Deserializer<'de> for Entry {
{ {
match self { match self {
Entry::Value(val) => val.deserialize_f64(visitor), Entry::Value(val) => val.deserialize_f64(visitor),
Entry::Statement(val) => Value::from(val).deserialize_f64(visitor),
_ => Err(UnknownError::from("f64").into()), _ => Err(UnknownError::from("f64").into()),
} }
} }
@ -542,6 +553,7 @@ impl<'de> Deserializer<'de> for Entry {
{ {
match self { match self {
Entry::Value(val) => val.deserialize_unit_struct(name, visitor), Entry::Value(val) => val.deserialize_unit_struct(name, visitor),
Entry::Statement(val) => Value::from(val).deserialize_unit_struct(name, visitor),
_ => Err(UnknownError::from("unit_struct").into()), _ => Err(UnknownError::from("unit_struct").into()),
} }
} }
@ -561,7 +573,7 @@ impl<'de> Deserializer<'de> for Entry {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self { match dbg!(self) {
Entry::Array(arr) => visitor.visit_seq(ArraySeq::new(arr)), Entry::Array(arr) => visitor.visit_seq(ArraySeq::new(arr)),
_ => Err(UnknownError::from("array2").into()), _ => Err(UnknownError::from("array2").into()),
} }
@ -571,7 +583,7 @@ impl<'de> Deserializer<'de> for Entry {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
match self { match dbg!(self) {
Entry::Array(arr) => visitor.visit_seq(ArraySeq::new(arr)), Entry::Array(arr) => visitor.visit_seq(ArraySeq::new(arr)),
_ => Err(UnknownError::from("tuple").into()), _ => Err(UnknownError::from("tuple").into()),
} }
@ -743,4 +755,23 @@ fn test_serde_entry() {
), ),
unwrap_err(crate::from_str(j)) unwrap_err(crate::from_str(j))
); );
let j = r#""{1 2 3}""#;
assert_eq!(
Entry::Array(
vec![
Value::from("1").into(),
Value::from("2").into(),
Value::from("3").into()
]
.into()
),
unwrap_err(crate::from_str(j))
);
}
pub(crate) fn string_is_array(string: &str) -> bool {
(string.starts_with('[') && string.ends_with(']'))
|| (string.starts_with('{') && string.ends_with('}'))
} }

View file

@ -1,5 +1,5 @@
use super::{Array, Entry}; use super::{Array, Entry};
use crate::entry::{Statement, Value}; use crate::entry::{string_is_array, Statement, Value};
use crate::error::UnknownError; use crate::error::UnknownError;
use crate::event::{EntryEvent, GroupStartEvent}; use crate::event::{EntryEvent, GroupStartEvent};
use crate::{Event, Item, Reader, Result, VdfError}; use crate::{Event, Item, Reader, Result, VdfError};
@ -70,7 +70,18 @@ impl Table {
key: Item::Item { content: key, .. }, key: Item::Item { content: key, .. },
value, value,
.. ..
}) => insert(&mut map, key, Value::from(value.into_content())), }) => {
if string_is_array(value.as_str()) {
let str = value.as_str();
insert(
&mut map,
key,
Array::from_space_separated(&str[1..str.len() - 1]),
)
} else {
insert(&mut map, key, Value::from(value.into_content()))
}
}
Event::Entry(EntryEvent { Event::Entry(EntryEvent {
key: Item::Statement { content: key, .. }, key: Item::Statement { content: key, .. },

View file

@ -1,5 +1,5 @@
use super::Entry; use super::Entry;
use crate::entry::{ParseItem, Statement}; use crate::entry::{string_is_array, ParseItem, Statement};
use crate::error::{ParseStringError, SerdeParseError}; use crate::error::{ParseStringError, SerdeParseError};
use crate::VdfError; use crate::VdfError;
use serde::de::{Error, Visitor}; use serde::de::{Error, Visitor};
@ -142,7 +142,7 @@ impl<'de> Deserializer<'de> for Value {
if let Ok(float) = f64::from_str(&self.0) { if let Ok(float) = f64::from_str(&self.0) {
return visitor.visit_f64(float); return visitor.visit_f64(float);
} }
if self.0.starts_with('[') && self.0.ends_with(']') { if string_is_array(&self.0) {
return self.deserialize_seq(visitor); return self.deserialize_seq(visitor);
} }
visitor.visit_string(self.0) visitor.visit_string(self.0)
@ -315,6 +315,7 @@ impl<'de> Deserializer<'de> for Value {
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
dbg!(&self);
Err(SerdeParseError::new("seq", self.0.as_ref(), 0..0, "").into()) Err(SerdeParseError::new("seq", self.0.as_ref(), 0..0, "").into())
} }

View file

@ -1,4 +1,4 @@
use crate::entry::{Entry, ParseItem}; use crate::entry::{string_is_array, Entry, ParseItem};
use crate::error::{ExpectToken, NoValidTokenError, ResultExt, SerdeParseError}; use crate::error::{ExpectToken, NoValidTokenError, ResultExt, SerdeParseError};
use crate::tokenizer::{SpannedToken, Tokenizer}; use crate::tokenizer::{SpannedToken, Tokenizer};
use crate::{Token, VdfError}; use crate::{Token, VdfError};
@ -127,7 +127,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
if let Ok(float) = f64::from_str(str.as_ref()) { if let Ok(float) = f64::from_str(str.as_ref()) {
return visitor.visit_f64(float).ensure_span(span, self.source()); return visitor.visit_f64(float).ensure_span(span, self.source());
} }
if str.starts_with('[') && str.ends_with(']') { if string_is_array(&str) {
self.push_peeked(token); self.push_peeked(token);
return self return self
.deserialize_seq(visitor) .deserialize_seq(visitor)
@ -350,7 +350,9 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
{ {
let token = self.peek().expect_token(STRING_ITEMS, self.source())?; let token = self.peek().expect_token(STRING_ITEMS, self.source())?;
let value_str = &self.source()[token.span.clone()]; let value_str = &self.source()[token.span.clone()];
if value_str.starts_with("\"[") && value_str.ends_with("]\"") { if (value_str.starts_with("\"[") && value_str.ends_with("]\""))
|| (value_str.starts_with("\"{") && value_str.ends_with("}\""))
{
let _ = self.next(); let _ = self.next();
let seq = &value_str[2..value_str.len() - 2]; let seq = &value_str[2..value_str.len() - 2];
let span = token.span.start + 2..token.span.end - 2; let span = token.span.start + 2..token.span.end - 2;

View file

@ -3,6 +3,6 @@
flex_array "[1.0 2.2]" flex_array "[1.0 2.2]"
tuple "[1 57]" tuple "[1 57]"
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
} }