vdflex

Crates.iovdflex
lib.rsvdflex
version0.1.1
sourcesrc
created_at2024-06-24 23:22:43.180084
updated_at2024-06-26 20:37:00.353778
descriptionA (de)serializer for the Valve Data File (VDF, a.k.a. KeyValues) format using Serde
homepage
repositoryhttps://github.com/ehedbor/vdflex
max_upload_size
id1282818
size109,400
Evan Hedbor (ehedbor)

documentation

README

VDFLex   Crates.io GitHub Actions Workflow Status Docs.rs GitHub

VDFLex is a (de)serialization library for parsing the Valve Data File format with serde. VDF—or more generally, KeyValues—is a data format developed by Valve for use in Steam and the Source engine.

LightmappedGeneric
{
    $basetexture "myassets\gravel01"
    $surfaceprop gravel
}

Installation

Add the following to your project's Cargo.toml:

[dependencies]
serde = { version = "1.0.0", features = ["derive"] }
vdflex = "0.1.1"

Feature Flags

  • default: No features
  • preserve_order: Preserve entry insertion order

Quick Start

use std::collections::BTreeMap;
use std::hash::Hash;
use serde::Serialize;

#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Serialize)]
struct AppId(u32);

#[derive(Serialize)]
#[serde(rename_all = "PascalCase")]
struct AppBuild {
    #[serde(rename = "AppID")]
    app_id: AppId,
    desc: String,
    content_root: String,
    build_output: String,
    depots: BTreeMap<AppId, Depot>
}

#[derive(Serialize)]
struct Depot {
    #[serde(rename = "FileMapping")]
    file_mappings: Vec<FileMapping>
}

#[derive(Serialize)]
struct FileMapping {
    #[serde(rename = "LocalPath")]
    local_path: String,
    #[serde(rename = "DepotPath")]
    depot_path: String,
}

fn main() -> vdflex::Result<()> {
    let mut depots = BTreeMap::new();
    depots.insert(AppId(1234), Depot {
        file_mappings: vec![FileMapping { 
            local_path: String::from("*"),
            depot_path: String::from("."),
        }],
    });
    
    let build_script = AppBuild {
        app_id: AppId(1234),
        desc: String::from("My SteamPipe build script"),
        content_root: String::from("..\\assets\\"),
        build_output: String::from("..\\build\\"),
        depots,
    };
    
    let text: String = vdflex::kv_to_string("AppBuild", &build_script)?;
    println!("{text}");
    // "AppBuild"
    // {
    //     "AppID" "1234"
    //     "BuildOutput" "..\build\"
    //     "ContentRoot" "..\assets\"
    //     "Depots"
    //     "Desc" "My SteamPipe build script"
    //     {
    //         "1234"
    //         {
    //             "FileMapping"
    //             {
    //                 "DepotPath" "."
    //                 "LocalPath" "*"
    //             }
    //         }
    //     }
    // }
  

    Ok(())
}

Supported Types

KeyValues is woefully underspecified, but in general it only supports strings and multimaps (objects). VDFLex attempts to support every Rust type, but not all types necessarily have an "idiomatic" or "useful" representation. These are the types that VDFlex supports and how they are represented in KeyValues:

Type Notes
bool Serialized to 1 or 0
integers KeyValues doesn't typically support i128 or u128
f32/f64 Some implementations only support f32. Non-finite floats are also poorly supported.
char/String/str -
Option KeyValues has no equivalent of null, so Some<T> is represented as T and None is simply omitted
Unit/Unit Structs Serialized like None
Unit Variants Represented as a string matching the name of the variant
Newtype Structs Represented as the wrapped type
Newtype Variants Represented as an object mapping the variant name to the wrapped type
Sequences/Tuples/Tuple Structs Represented by repeating the key for each element in the sequence
Tuple Variants Represented by a map containing a sequence of the tuple's fields, using the variant name as the key
Maps/Structs Represented by objects (a curly bracket-enclosed list of key-value pairs)
Struct Variants Represented as an object mapping the variant name to the struct representation of its fields

Limitations

  • The Bytes type is unsupported, as there is no clear way to represent binary data in KeyValues.
  • Sequences are weird. It's not possible to serialize top-level or nested sequences. See [Error::UnrepresentableSequence] for more.

Missing Features

This library is in an early state. As such, many features have not yet been implemented. Some missing features include:

  • Deserialization
    • Text parsing
    • Conversion to Rust types
  • An easier API for [Object]
  • A keyvalues! macro to create [Object]s
  • Conditional tags
    • The [ser::Formatter] API supports conditional tags, but this is unsupported for the serde API.
  • #base and #include directives
    • The [ser::Formatter] API supports macro formatting, but the serde API treats macros like normal fields.

License

This library is licensed under the MIT license (https://opensource.org/license/MIT).

Commit count: 45

cargo fmt