allow deserializing from Entry

This commit is contained in:
Robin Appelman 2023-12-19 00:49:29 +01:00
commit ebb940847d
12 changed files with 973 additions and 8 deletions

View file

@ -1,4 +1,6 @@
use super::Entry; use super::Entry;
use crate::VdfError;
use serde::de::{DeserializeSeed, SeqAccess};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
@ -37,3 +39,31 @@ impl DerefMut for Array {
&mut self.0 &mut self.0
} }
} }
pub(crate) struct ArraySeq {
iter: std::vec::IntoIter<Entry>,
}
impl ArraySeq {
pub(crate) fn new(array: Array) -> Self {
ArraySeq {
iter: array.0.into_iter(),
}
}
}
impl<'de> SeqAccess<'de> for ArraySeq {
type Error = VdfError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
let next = match self.iter.next() {
Some(next) => next,
None => return Ok(None),
};
seed.deserialize(next).map(Some)
}
}

View file

@ -3,8 +3,8 @@ mod statement;
mod table; mod table;
mod value; mod value;
use crate::error::{ParseEntryError, ParseItemError, ParseStringError}; use crate::error::{ParseEntryError, ParseItemError, ParseStringError, UnknownError};
use crate::Item; use crate::{Item, VdfError};
pub use array::Array; pub use array::Array;
pub use statement::Statement; pub use statement::Statement;
use std::any::type_name; use std::any::type_name;
@ -177,7 +177,9 @@ macro_rules! from_str {
); );
} }
use serde::de::{Error, MapAccess, SeqAccess, Visitor}; use crate::entry::array::ArraySeq;
use crate::entry::table::TableSeq;
use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
from_str!(for IpAddr Ipv4Addr Ipv6Addr SocketAddr SocketAddrV4 SocketAddrV6); from_str!(for IpAddr Ipv4Addr Ipv6Addr SocketAddr SocketAddrV4 SocketAddrV6);
@ -330,6 +332,378 @@ impl<'de> Deserialize<'de> for Entry {
} }
} }
impl<'de> Deserializer<'de> for Entry {
type Error = VdfError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Table(table) => visitor.visit_map(TableSeq::new(table)),
Entry::Array(array) => visitor.visit_seq(ArraySeq::new(array)),
Entry::Value(val) => val.deserialize_any(visitor),
Entry::Statement(val) => visitor.visit_string(val.into()),
}
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_bool(visitor),
_ => Err(UnknownError::from("bool").into()),
}
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_i8(visitor),
_ => Err(UnknownError::from("i8").into()),
}
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_i16(visitor),
_ => Err(UnknownError::from("i16").into()),
}
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_i32(visitor),
_ => Err(UnknownError::from("i32").into()),
}
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_i64(visitor),
_ => Err(UnknownError::from("i64").into()),
}
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_u8(visitor),
_ => Err(UnknownError::from("u8").into()),
}
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_u16(visitor),
_ => Err(UnknownError::from("u16").into()),
}
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_u32(visitor),
_ => Err(UnknownError::from("u32").into()),
}
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_u64(visitor),
_ => Err(UnknownError::from("u64").into()),
}
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_f32(visitor),
_ => Err(UnknownError::from("f32").into()),
}
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_f64(visitor),
_ => Err(UnknownError::from("f64").into()),
}
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_char(visitor),
Entry::Statement(val) => Value::from(val).deserialize_char(visitor),
_ => Err(UnknownError::from("char").into()),
}
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_str(visitor),
Entry::Statement(val) => Value::from(val).deserialize_str(visitor),
_ => Err(UnknownError::from("str").into()),
}
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_string(visitor),
Entry::Statement(val) => Value::from(val).deserialize_string(visitor),
_ => Err(UnknownError::from("string1").into()),
}
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_bytes(visitor),
_ => Err(UnknownError::from("bytes").into()),
}
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_bool(visitor),
_ => Err(UnknownError::from("bytes buf").into()),
}
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_option(visitor),
Entry::Statement(val) => Value::from(val).deserialize_option(visitor),
_ => Err(UnknownError::from("option").into()),
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_unit(visitor),
Entry::Statement(val) => Value::from(val).deserialize_unit(visitor),
_ => Err(UnknownError::from("unit").into()),
}
}
fn deserialize_unit_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Value(val) => val.deserialize_unit_struct(name, visitor),
_ => Err(UnknownError::from("unit_struct").into()),
}
}
fn deserialize_newtype_struct<V>(
self,
_name: &'static str,
_visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
todo!()
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Array(arr) => visitor.visit_seq(ArraySeq::new(arr)),
_ => Err(UnknownError::from("array2").into()),
}
}
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Array(arr) => visitor.visit_seq(ArraySeq::new(arr)),
_ => Err(UnknownError::from("tuple").into()),
}
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
_len: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Array(arr) => visitor.visit_seq(ArraySeq::new(arr)),
_ => Err(UnknownError::from("tuple_struct").into()),
}
}
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
Entry::Table(table) => visitor.visit_map(TableSeq::new(table)),
_ => Err(UnknownError::from("map").into()),
}
}
fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_map(visitor)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
struct EnVarAccess {
variant: Value,
value: Entry,
}
struct EnValAccess {
value: Entry,
}
impl<'de> EnumAccess<'de> for EnVarAccess {
type Error = VdfError;
type Variant = EnValAccess;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
{
seed.deserialize(self.variant)
.map(|v| (v, EnValAccess { value: self.value }))
}
}
impl<'de> VariantAccess<'de> for EnValAccess {
type Error = VdfError;
fn unit_variant(self) -> Result<(), Self::Error> {
Err(UnknownError::from("unit").into())
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
seed.deserialize(self.value)
}
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.value.deserialize_seq(visitor)
}
fn struct_variant<V>(
self,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.value.deserialize_map(visitor)
}
}
match self {
Entry::Table(table) if table.len() == 1 => {
let (variant, value) = HashMap::from(table).into_iter().next().unwrap();
visitor.visit_enum(EnVarAccess {
variant: variant.into(),
value,
})
}
_ => Err(UnknownError::from("enum").into()),
}
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_string(visitor)
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_any(visitor)
}
}
#[cfg(test)] #[cfg(test)]
#[track_caller] #[track_caller]
fn unwrap_err<T>(r: Result<T, crate::VdfError>) -> T { fn unwrap_err<T>(r: Result<T, crate::VdfError>) -> T {

View file

@ -1,7 +1,9 @@
use super::{Array, Entry}; use super::{Array, Entry};
use crate::entry::{Statement, Value}; use crate::entry::{Statement, Value};
use crate::error::UnknownError;
use crate::event::{EntryEvent, GroupStartEvent}; use crate::event::{EntryEvent, GroupStartEvent};
use crate::{Event, Item, Reader, Result}; use crate::{Event, Item, Reader, Result, VdfError};
use serde::de::{DeserializeSeed, MapAccess};
use serde::{Deserialize, Serialize, Serializer}; use serde::{Deserialize, Serialize, Serializer};
use std::collections::hash_map; use std::collections::hash_map;
use std::collections::HashMap; use std::collections::HashMap;
@ -53,6 +55,11 @@ fn insert<K: Into<String>, V: Into<Entry>>(map: &mut HashMap<String, Entry>, key
} }
impl Table { impl Table {
pub fn load_from_str(input: &str) -> Result<Table> {
let mut reader = Reader::from(input);
Self::load(&mut reader)
}
/// Load a table from the given `Reader`. /// Load a table from the given `Reader`.
pub fn load(reader: &mut Reader) -> Result<Table> { pub fn load(reader: &mut Reader) -> Result<Table> {
let mut map = HashMap::new(); let mut map = HashMap::new();
@ -89,6 +96,12 @@ impl From<Table> for Entry {
} }
} }
impl From<Table> for HashMap<String, Entry> {
fn from(table: Table) -> Self {
table.0
}
}
impl Deref for Table { impl Deref for Table {
type Target = HashMap<String, Entry>; type Target = HashMap<String, Entry>;
@ -97,6 +110,50 @@ impl Deref for Table {
} }
} }
pub(crate) struct TableSeq {
iter: hash_map::IntoIter<String, Entry>,
next_item: Option<Entry>,
}
impl TableSeq {
pub(crate) fn new(table: Table) -> Self {
TableSeq {
iter: table.0.into_iter(),
next_item: None,
}
}
}
impl<'de> MapAccess<'de> for TableSeq {
type Error = VdfError;
fn next_key_seed<K>(&mut self, seed: K) -> std::result::Result<Option<K::Value>, Self::Error>
where
K: DeserializeSeed<'de>,
{
let (key, value) = match self.iter.next() {
Some(pair) => pair,
None => {
return Ok(None);
}
};
self.next_item = Some(value);
seed.deserialize(Value::from(key)).map(Some)
}
fn next_value_seed<V>(&mut self, seed: V) -> std::result::Result<V::Value, Self::Error>
where
V: DeserializeSeed<'de>,
{
let item = match self.next_item.take() {
Some(item) => item,
None => return Err(UnknownError::from("double take value").into()),
};
seed.deserialize(item)
}
}
#[cfg(test)] #[cfg(test)]
#[track_caller] #[track_caller]
fn unwrap_err<T>(r: Result<T, crate::VdfError>) -> T { fn unwrap_err<T>(r: Result<T, crate::VdfError>) -> T {

View file

@ -1,4 +1,7 @@
use super::Entry; use super::Entry;
use crate::entry::{ParseItem, Statement};
use crate::error::{ParseStringError, SerdeParseError};
use crate::VdfError;
use serde::de::{Error, Visitor}; use serde::de::{Error, Visitor};
use serde::{Deserialize, Deserializer, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
use std::borrow::Cow; use std::borrow::Cow;
@ -26,6 +29,12 @@ impl From<String> for Value {
} }
} }
impl From<Statement> for Value {
fn from(value: Statement) -> Value {
Value(value.into())
}
}
impl From<Value> for Entry { impl From<Value> for Entry {
fn from(value: Value) -> Self { fn from(value: Value) -> Self {
Entry::Value(value) Entry::Value(value)
@ -46,6 +55,13 @@ impl Deref for Value {
} }
} }
impl Value {
/// Try to convert the entry to the given type.
pub fn to<T: ParseItem>(self) -> Result<T, ParseStringError> {
T::from_str(&self.0)
}
}
impl<'de> Deserialize<'de> for Value { impl<'de> Deserialize<'de> for Value {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
@ -107,6 +123,260 @@ impl<'de> Deserialize<'de> for Value {
} }
} }
impl<'de> Deserializer<'de> for Value {
type Error = VdfError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
if let Ok(int) = i64::from_str(&self.0) {
return visitor.visit_i64(int);
}
if let Ok(float) = f64::from_str(&self.0) {
return visitor.visit_f64(float);
}
if self.0.starts_with('[') && self.0.ends_with(']') {
return self.deserialize_seq(visitor);
}
visitor.visit_string(self.0)
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_bool(self.to()?)
}
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_i8(self.to()?)
}
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_i16(self.to()?)
}
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_i32(self.to()?)
}
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_i64(self.to()?)
}
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_u8(self.to()?)
}
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_u16(self.to()?)
}
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_u32(self.to()?)
}
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_u64(self.to()?)
}
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_f32(self.to()?)
}
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_f64(self.to()?)
}
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let mut chars = self.0.chars();
match (chars.next(), chars.next()) {
(Some(_), None) => Ok(()),
_ => Err(SerdeParseError::new("char", &self.0, 0..0, "")),
}?;
visitor.visit_str(&self.0)
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_str(&self.0)
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_string(self.0)
}
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_bytes(self.0.as_bytes())
}
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_byte_buf(self.0.into_bytes())
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
if self.0.is_empty() {
return visitor.visit_none();
}
visitor.visit_some(self)
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
if !self.0.is_empty() {
return Err(SerdeParseError::new("unit", self.0.as_ref(), 0..0, "").into());
}
visitor.visit_unit()
}
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
if !self.0.is_empty() {
return Err(SerdeParseError::new("unit", self.0.as_ref(), 0..0, "").into());
}
visitor.visit_unit()
}
fn deserialize_newtype_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_seq<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(SerdeParseError::new("seq", self.0.as_ref(), 0..0, "").into())
}
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
_len: usize,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_map<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(SerdeParseError::new("map", self.0.as_ref(), 0..0, "").into())
}
fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
_visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(SerdeParseError::new("struct", self.0.as_ref(), 0..0, "").into())
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
_visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(SerdeParseError::new("map", self.0.as_ref(), 0..0, "").into())
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_any(visitor)
}
}
#[cfg(test)] #[cfg(test)]
#[track_caller] #[track_caller]
fn unwrap_err<T>(r: Result<T, crate::VdfError>) -> T { fn unwrap_err<T>(r: Result<T, crate::VdfError>) -> T {
@ -121,3 +391,9 @@ fn test_serde_value() {
let j = r#""foo bar""#; let j = r#""foo bar""#;
assert_eq!(Value("foo bar".into()), unwrap_err(crate::from_str(j))); assert_eq!(Value("foo bar".into()), unwrap_err(crate::from_str(j)));
} }
#[test]
fn test_serde_from_value() {
let j = Value::from("1");
assert_eq!(true, unwrap_err(crate::from_entry(j.into())));
}

View file

@ -171,6 +171,16 @@ pub struct UnknownError {
src: String, src: String,
} }
impl From<&str> for UnknownError {
fn from(value: &str) -> Self {
UnknownError {
error: value.to_string(),
err_span: (0..0).into(),
src: String::new(),
}
}
}
/// A token that wasn't expected was found while parsing /// A token that wasn't expected was found while parsing
#[derive(Debug, Clone, Diagnostic)] #[derive(Debug, Clone, Diagnostic)]
#[diagnostic(code(vmt_reader::unexpected_token))] #[diagnostic(code(vmt_reader::unexpected_token))]

View file

@ -9,7 +9,7 @@ mod tokenizer;
pub use error::VdfError; pub use error::VdfError;
pub type Result<T, E = VdfError> = std::result::Result<T, E>; pub type Result<T, E = VdfError> = std::result::Result<T, E>;
pub use crate::serde::from_str; pub use crate::serde::{from_entry, from_str};
pub use event::{EntryEvent, Event, GroupEndEvent, GroupStartEvent, Item}; pub use event::{EntryEvent, Event, GroupEndEvent, GroupStartEvent, Item};
pub use lexer::Token; pub use lexer::Token;
pub use reader::Reader; pub use reader::Reader;

View file

@ -1,4 +1,4 @@
use crate::entry::ParseItem; use crate::entry::{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};
@ -92,6 +92,13 @@ where
T::deserialize(&mut deserializer) T::deserialize(&mut deserializer)
} }
pub fn from_entry<'a, T>(entry: Entry) -> Result<T>
where
T: Deserialize<'a>,
{
T::deserialize(entry)
}
const VALUE_TOKEN: &[Token] = &[ const VALUE_TOKEN: &[Token] = &[
Token::Item, Token::Item,
Token::QuotedItem, Token::QuotedItem,

View file

@ -4,7 +4,7 @@ use std::collections::BTreeMap;
use std::fs::read_to_string; use std::fs::read_to_string;
use test_case::test_case; use test_case::test_case;
use vdf_reader::entry::Table; use vdf_reader::entry::Table;
use vdf_reader::from_str; use vdf_reader::{from_entry, from_str};
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
enum Expected { enum Expected {
@ -197,7 +197,9 @@ fn test_serde(path: &str) {
fn test_serde_table(path: &str) { fn test_serde_table(path: &str) {
let raw = read_to_string(path).unwrap(); let raw = read_to_string(path).unwrap();
match from_str::<Table>(&raw) { match from_str::<Table>(&raw) {
Ok(result) => insta::assert_ron_snapshot!(format!("table__{}", path), result), Ok(result) => {
insta::assert_ron_snapshot!(format!("table__{}", path), result);
}
Err(e) => { Err(e) => {
let handler = GraphicalReportHandler::new_themed(GraphicalTheme::unicode_nocolor()); let handler = GraphicalReportHandler::new_themed(GraphicalTheme::unicode_nocolor());
let mut out = String::new(); let mut out = String::new();
@ -206,3 +208,15 @@ fn test_serde_table(path: &str) {
} }
} }
} }
#[test_case("tests/data/concrete.vmt")]
#[test_case("tests/data/messy.vdf")]
#[test_case("tests/data/DialogConfigOverlay_1280x720.vdf")]
#[test_case("tests/data/serde_array_type.vdf")]
fn test_serde_from_table(path: &str) {
let raw = read_to_string(path).unwrap();
let result = Table::load_from_str(&raw).unwrap();
let material: Expected = from_entry(result.into()).expect("table to material");
insta::assert_ron_snapshot!(format!("table_to_material__{}", path), material);
}

View file

@ -0,0 +1,152 @@
---
source: tests/serde.rs
expression: material
---
UserConfigData(
Steam: UserConfigDataSteam(
cached: UserConfigDataSteamCached(
r#OverlaySplash.res: {},
),
),
FriendsMainDialog: {
"xpos": 1028,
"ypos": 280,
"wide": 252,
"tall": 440,
"FriendPanelSelf": {},
"FriendsDialogSheet": UserConfigDataFriendsMainDialogFriendsDialogSheet(
FriendsFriendsPage: UserConfigDataFriendsMainDialogFriendsDialogSheetFriendsPage(
BuddyList: {
"0_collapsed": false,
"1_collapsed": false,
"2_collapsed": false,
"3_collapsed": false,
"4_collapsed": false,
"5_collapsed": false,
"allfriends_collapsed": false,
},
),
FriendsClansPage: UserConfigDataFriendsMainDialogFriendsDialogSheetFriendsPage(
BuddyList: {
"0_collapsed": false,
"1_collapsed": false,
"2_collapsed": false,
"3_collapsed": false,
},
),
),
"FriendsState": {},
},
Servers: UserConfigDataServers(
r#DialogServerBrowser.res: {
"xpos": 0,
"ypos": 0,
"wide": 1280,
"tall": 720,
"GameTabs": UserConfigDataServersDialogGameTabs(
InternetGames: GameListHaver(
gamelist: GameList(
r##ServerBrowser_Password_hidden: false,
r##ServerBrowser_Bots_hidden: true,
r##ServerBrowser_Secure_hidden: false,
r##ServerBrowser_Servers_hidden: false,
r##ServerBrowser_IPAddress_hidden: true,
r##ServerBrowser_Game_hidden: false,
r##ServerBrowser_Players_hidden: false,
r##ServerBrowser_Map_hidden: false,
r##ServerBrowser_Latency_hidden: false,
sort_column: "#ServerBrowser_Latency",
sort_column_secondary: None,
sort_column_asc: true,
sort_column_secondary_asc: true,
),
),
FavoriteGames: GameListHaver(
gamelist: GameList(
r##ServerBrowser_Password_hidden: false,
r##ServerBrowser_Bots_hidden: true,
r##ServerBrowser_Secure_hidden: false,
r##ServerBrowser_Servers_hidden: false,
r##ServerBrowser_IPAddress_hidden: true,
r##ServerBrowser_Game_hidden: false,
r##ServerBrowser_Players_hidden: false,
r##ServerBrowser_Map_hidden: false,
r##ServerBrowser_Latency_hidden: false,
sort_column: "#ServerBrowser_Latency",
sort_column_secondary: None,
sort_column_asc: true,
sort_column_secondary_asc: true,
),
),
HistoryGames: GameListHaver(
gamelist: GameList(
r##ServerBrowser_Password_hidden: false,
r##ServerBrowser_Bots_hidden: true,
r##ServerBrowser_Secure_hidden: false,
r##ServerBrowser_Servers_hidden: false,
r##ServerBrowser_IPAddress_hidden: true,
r##ServerBrowser_Game_hidden: false,
r##ServerBrowser_Players_hidden: false,
r##ServerBrowser_Map_hidden: false,
r##ServerBrowser_Latency_hidden: false,
sort_column: "#ServerBrowser_LastPlayed",
sort_column_secondary: Some("#ServerBrowser_Latency"),
sort_column_asc: true,
sort_column_secondary_asc: true,
),
),
SpectateGames: GameListHaver(
gamelist: GameList(
r##ServerBrowser_Password_hidden: false,
r##ServerBrowser_Bots_hidden: true,
r##ServerBrowser_Secure_hidden: false,
r##ServerBrowser_Servers_hidden: false,
r##ServerBrowser_IPAddress_hidden: true,
r##ServerBrowser_Game_hidden: false,
r##ServerBrowser_Players_hidden: false,
r##ServerBrowser_Map_hidden: false,
r##ServerBrowser_Latency_hidden: false,
sort_column: "#ServerBrowser_Latency",
sort_column_secondary: None,
sort_column_asc: true,
sort_column_secondary_asc: true,
),
),
LanGames: GameListHaver(
gamelist: GameList(
r##ServerBrowser_Password_hidden: false,
r##ServerBrowser_Bots_hidden: true,
r##ServerBrowser_Secure_hidden: false,
r##ServerBrowser_Servers_hidden: false,
r##ServerBrowser_IPAddress_hidden: true,
r##ServerBrowser_Game_hidden: false,
r##ServerBrowser_Players_hidden: false,
r##ServerBrowser_Map_hidden: false,
r##ServerBrowser_Latency_hidden: false,
sort_column: "#ServerBrowser_Latency",
sort_column_secondary: None,
sort_column_asc: true,
sort_column_secondary_asc: true,
),
),
FriendsGames: GameListHaver(
gamelist: GameList(
r##ServerBrowser_Password_hidden: false,
r##ServerBrowser_Bots_hidden: true,
r##ServerBrowser_Secure_hidden: false,
r##ServerBrowser_Servers_hidden: false,
r##ServerBrowser_IPAddress_hidden: true,
r##ServerBrowser_Game_hidden: false,
r##ServerBrowser_Players_hidden: false,
r##ServerBrowser_Map_hidden: false,
r##ServerBrowser_Latency_hidden: false,
sort_column: "#ServerBrowser_Latency",
sort_column_secondary: None,
sort_column_asc: true,
sort_column_secondary_asc: true,
),
),
),
},
),
)

View file

@ -0,0 +1,14 @@
---
source: tests/serde.rs
expression: material
---
LightmappedGeneric(
r#$baseTexture: "cp_mountainlab/concrete/concretefloor003",
r#$bumpmap: "concrete/concretefloor007b_height-ssbump",
r#$ssbump: true,
r#%keywords: "tf",
r#$detail: "overlays/detail001",
r#$detailscale: 1.9,
r#$detailblendmode: 0,
r#$detailblendfactor: 1.0,
)

View file

@ -0,0 +1,16 @@
---
source: tests/serde.rs
expression: material
---
r#Resource/specificPanel.res(
empty: (),
array: [
1,
2,
3,
],
windows_path: "C:\\test\\no newline",
r#\\"$translucent": true,
r#$envmaptint: 0.5,
r#.5: 0.5,
)

View file

@ -0,0 +1,15 @@
---
source: tests/serde.rs
expression: material
---
Types(
fixed_array: (1, 2, 3),
flex_array: [
1.0,
2.2,
],
tuple: (true, 57),
single: 1.2,
triple: (1.2, 1.3, 1.4),
single_int: 2.0,
)