move to serde_core

This commit is contained in:
Robin Appelman 2025-10-22 21:46:10 +02:00
commit cf230951a9
10 changed files with 282 additions and 40 deletions

19
Cargo.lock generated
View file

@ -404,18 +404,28 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.218"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.218"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
@ -604,6 +614,7 @@ dependencies = [
"miette",
"parse-display",
"serde",
"serde_core",
"test-case",
"thiserror 2.0.11",
"walkdir",

View file

@ -12,7 +12,7 @@ logos = "0.14.0"
thiserror = "2.0.11"
miette = "7.5.0"
parse-display = "0.9.0"
serde = { version = "1.0.200", features = ["derive"] }
serde_core = "1.0.228"
[dev-dependencies]
test-case = "3.3.1"
@ -20,3 +20,4 @@ insta = { version = "1.38.0", features = ["ron"] }
miette = { version = "7.2.0", features = ["fancy"] }
walkdir = "2.5.0"
maplit = "1.0.2"
serde = { version = "1.0.228", features = ["derive"] }

164
app.vdf Normal file
View file

@ -0,0 +1,164 @@
"appinfo"
{
"appid" "232250"
"common"
{
"name" "Team Fortress 2 Dedicated Server"
"type" "Tool"
"releasestate" "released"
"oslist" "windows,linux"
"parent" "440"
"freetodownload" "1"
"gameid" "232250"
"exfgls" "9"
}
"extended"
{
"checkpkgstate" "1"
"developer" ""
"gamedir" "ValveTestApp232250"
"homepage" ""
"icon" ""
"noservers" "0"
"sourcegame" "1"
"state" "eStateComingSoonNoPreload"
"visibleonlywhensubscribed" "1"
}
"config"
{
"verifyupdates" "1"
"contenttype" "3"
"installdir" "Team Fortress 2 Dedicated Server"
}
"depots"
{
"232250"
{
"manifests"
{
"public"
{
"gid" "3423298312000784891"
"size" "13557339255"
"download" "8923361280"
}
"prerelease"
{
"gid" "3423298312000784891"
"size" "13557339255"
"download" "8923361280"
}
"valve_ds"
{
"gid" "3423298312000784891"
"size" "13557339255"
"download" "8923361280"
}
}
}
"232255"
{
"config"
{
"oslist" "windows"
}
"manifests"
{
"public"
{
"gid" "6628420416233102704"
"size" "267733389"
"download" "88870304"
}
"prerelease"
{
"gid" "6628420416233102704"
"size" "267733389"
"download" "88870304"
}
"valve_ds"
{
"gid" "6628420416233102704"
"size" "267733389"
"download" "88870304"
}
}
}
"232256"
{
"config"
{
"oslist" "linux"
}
"manifests"
{
"public"
{
"gid" "4606186468524235451"
"size" "155992583"
"download" "39774800"
}
"prerelease"
{
"gid" "4606186468524235451"
"size" "155992583"
"download" "39774800"
}
"valve_ds"
{
"gid" "4606186468524235451"
"size" "155992583"
"download" "39774800"
}
}
}
"232257"
{
"config"
{
"oslist" "linux"
}
"manifests"
{
"public"
{
"gid" "4797708003880603728"
"size" "9989"
"download" "2608"
}
"prerelease"
{
"gid" "4797708003880603728"
"size" "9989"
"download" "2608"
}
"valve_ds"
{
"gid" "4797708003880603728"
"size" "9989"
"download" "2608"
}
}
}
"overridescddb" "1"
"branches"
{
"public"
{
"buildid" "18450794"
"timeupdated" "1747175459"
}
"prerelease"
{
"buildid" "18450794"
"timeupdated" "1747175467"
}
"valve_ds"
{
"buildid" "18450794"
"description" "The version Valve dedicated servers will sync to"
"timeupdated" "1747175424"
}
}
}
}

View file

@ -2,13 +2,12 @@ use super::{Entry, Table};
use crate::entry::Value;
use crate::error::{ParseStringError, UnknownError};
use crate::VdfError;
use serde::de::{DeserializeSeed, SeqAccess};
use serde::{Deserialize, Serialize};
use serde_core::de::{DeserializeSeed, SeqAccess};
use serde_core::{Deserialize, Deserializer, Serialize, Serializer};
use std::ops::{Deref, DerefMut};
/// An array of entries (items that have the same key).
#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize, Default)]
#[serde(transparent)]
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct Array(Vec<Entry>);
impl Array {
@ -23,6 +22,24 @@ impl Array {
}
}
impl<'de> Deserialize<'de> for Array {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
<Vec<Entry>>::deserialize(deserializer).map(Array)
}
}
impl Serialize for Array {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
impl From<Vec<Entry>> for Array {
fn from(value: Vec<Entry>) -> Self {
Array(value)

View file

@ -16,8 +16,7 @@ pub use table::Table;
pub use value::Value;
/// The kinds of entry.
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
#[serde(untagged)]
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Entry {
/// A table.
Table(Table),
@ -32,6 +31,20 @@ pub enum Entry {
Statement(Statement),
}
impl Serialize for Entry {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Entry::Table(entry) => entry.serialize(serializer),
Entry::Array(entry) => entry.serialize(serializer),
Entry::Value(entry) => entry.serialize(serializer),
Entry::Statement(entry) => entry.serialize(serializer),
}
}
}
impl From<Item<'_>> for Entry {
fn from(item: Item) -> Self {
match item {
@ -218,8 +231,10 @@ macro_rules! from_str {
use crate::entry::array::{ArraySeq, TableArraySeq};
use crate::entry::table::TableSeq;
use serde::de::{DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use serde_core::de::{
DeserializeSeed, EnumAccess, Error, MapAccess, SeqAccess, VariantAccess, Visitor,
};
use serde_core::{Deserialize, Deserializer, Serialize, Serializer};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
from_str!(for IpAddr Ipv4Addr Ipv6Addr SocketAddr SocketAddrV4 SocketAddrV6);
from_str!(for i8 i16 i32 i64 isize u8 u16 u32 u64 usize f32 f64);

View file

@ -1,13 +1,30 @@
use super::Entry;
use serde::{Deserialize, Serialize};
use serde_core::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::Cow;
use std::ops::Deref;
/// A statement.
#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize, Default)]
#[serde(transparent)]
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct Statement(String);
impl<'de> Deserialize<'de> for Statement {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
String::deserialize(deserializer).map(Statement)
}
}
impl Serialize for Statement {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
impl From<Cow<'_, str>> for Statement {
fn from(value: Cow<'_, str>) -> Self {
Statement(value.into())

View file

@ -3,16 +3,35 @@ use crate::entry::{string_is_array, Statement, Value};
use crate::error::UnknownError;
use crate::event::{EntryEvent, GroupStartEvent, ValueContinuationEvent};
use crate::{Event, Item, Reader, Result, VdfError};
use serde::de::{DeserializeSeed, MapAccess};
use serde::{Deserialize, Serialize, Serializer};
use serde_core::de::{DeserializeSeed, MapAccess};
use serde_core::{Deserialize, Deserializer, Serialize, Serializer};
use std::collections::hash_map;
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
/// A table of entries.
#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize, Default)]
#[serde(transparent)]
pub struct Table(#[serde(serialize_with = "ordered_map")] HashMap<String, Entry>); // todo: switch to a map that maintains item order
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct Table(HashMap<String, Entry>); // todo: switch to a map that maintains item order
impl<'de> Deserialize<'de> for Table {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
HashMap::deserialize(deserializer).map(Table)
}
}
impl Serialize for Table {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
use std::collections::BTreeMap;
let ordered: BTreeMap<_, _> = self.0.iter().collect();
ordered.serialize(serializer)
}
}
impl From<HashMap<String, Entry>> for Table {
fn from(value: HashMap<String, Entry>) -> Self {
@ -20,18 +39,6 @@ impl From<HashMap<String, Entry>> for Table {
}
}
fn ordered_map<S, K: Ord + Serialize, V: Serialize>(
value: &HashMap<K, V>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use std::collections::BTreeMap;
let ordered: BTreeMap<_, _> = value.iter().collect();
ordered.serialize(serializer)
}
fn insert<K: Into<String>, V: Into<Entry>>(map: &mut HashMap<String, Entry>, key: K, value: V) {
let key = key.into();
let value = value.into();

View file

@ -2,16 +2,24 @@ use super::Entry;
use crate::entry::{string_is_array, ParseItem, Statement};
use crate::error::{ParseStringError, SerdeParseError};
use crate::VdfError;
use serde::de::{Error, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use serde_core::de::{Error, Visitor};
use serde_core::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::Cow;
use std::fmt::Formatter;
use std::ops::{Deref, DerefMut};
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Default)]
#[serde(transparent)]
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct Value(String);
impl Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
impl From<Cow<'_, str>> for Value {
fn from(value: Cow<'_, str>) -> Value {
Value(value.into())

View file

@ -464,7 +464,7 @@ impl<'source> ExpectToken<'source> for SpannedToken {
}
}
impl serde::de::Error for VdfError {
impl serde_core::de::Error for VdfError {
fn custom<T>(msg: T) -> Self
where
T: Display,

View file

@ -3,8 +3,10 @@ use crate::error::{ExpectToken, NoValidTokenError, ResultExt, SerdeParseError, U
use crate::tokenizer::{SpannedToken, Tokenizer};
use crate::{Token, VdfError};
use logos::Span;
use serde::de::{self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, VariantAccess, Visitor};
use serde::Deserialize;
use serde_core::de::{
self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, VariantAccess, Visitor,
};
use serde_core::Deserialize;
use std::borrow::Cow;
type Result<T, E = VdfError> = std::result::Result<T, E>;