Skip to content

Commit 6162f6e

Browse files
committed
wip
1 parent 4965425 commit 6162f6e

6 files changed

Lines changed: 243 additions & 14 deletions

File tree

steamkit-vdf/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This crate is designed to be a bunch of tools for interacting with the Steam API
1313

1414
[dependencies]
1515
thiserror = "2.0"
16+
cfg-if = "1.0"
1617

1718
[dependencies.regex-lite]
1819
version = "0.1"
@@ -26,3 +27,4 @@ optional = true
2627
default = ["regex"]
2728
regex = ["dep:regex"]
2829
regex-lite = ["dep:regex-lite"]
30+
precision = []

steamkit-vdf/src/entry.rs

Lines changed: 0 additions & 8 deletions
This file was deleted.

steamkit-vdf/src/error.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,9 @@ pub type Result<T> = std::result::Result<T, Error>;
44
pub enum Error {
55
#[error("Failed to parse input")]
66
Parse,
7+
#[error("Only {variant} can be converted to {output_type}")]
8+
InvalidConversion {
9+
variant: &'static str,
10+
output_type: &'static str,
11+
},
712
}

steamkit-vdf/src/lib.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1-
pub mod entry;
2-
pub mod error;
3-
pub mod parser;
1+
mod error;
2+
mod parser;
3+
mod types;
4+
5+
pub use error::*;
6+
pub use parser::*;
7+
pub use types::*;

steamkit-vdf/src/parser.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{entry::Entry, error::Error};
1+
use std::io::{BufReader, Cursor, Read};
22

33
#[cfg(all(feature = "regex", feature = "regex-lite"))]
44
compile_error!("Features 'regex' and 'regex-lite' cannot be enabled at the same time.");
@@ -7,6 +7,8 @@ use regex::Regex;
77
#[cfg(feature = "regex-lite")]
88
use regex_lite::Regex;
99

10+
use crate::{Group, Result};
11+
1012
thread_local! {
1113
static INT_REGEX: Regex = Regex::new(r"^\-?\d+$").unwrap();
1214
static FLOAT_REGEX: Regex = Regex::new(r"\-?\d+\.\d+$").unwrap();
@@ -19,6 +21,14 @@ pub struct Options {
1921
pub conditionals: Option<Vec<String>>,
2022
}
2123

22-
pub fn parse(input: &str, options: &Options) -> Result<Entry, Error> {
23-
todo!()
24+
pub fn from_str(input: &str, options: &Options) -> Result<Group> {
25+
let reader = Cursor::new(input.as_bytes());
26+
from_reader(reader, options)
27+
}
28+
29+
pub fn from_reader<R: Read>(input: R, options: &Options) -> Result<Group> {
30+
let mut reader = BufReader::new(input);
31+
let mut entries = vec![];
32+
33+
Ok(Group { entries })
2434
}

steamkit-vdf/src/types.rs

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
use crate::{Error, Result};
2+
3+
cfg_if::cfg_if! {
4+
if #[cfg(feature = "precision")] {
5+
pub type Int = i64;
6+
pub type Float = f64;
7+
8+
const FLOAT_TYPE: &str = "f64";
9+
const INT_TYPE: &str = "i64";
10+
} else {
11+
pub type Int = i32;
12+
pub type Float = f32;
13+
14+
const FLOAT_TYPE: &str = "f32";
15+
const INT_TYPE: &str = "i32";
16+
}
17+
}
18+
19+
#[derive(Debug, Clone)]
20+
pub enum Value {
21+
Float(Float),
22+
Int(Int),
23+
String(String),
24+
Bool(bool),
25+
Group(Group),
26+
}
27+
28+
impl From<Group> for Value {
29+
fn from(group: Group) -> Self {
30+
Value::Group(group)
31+
}
32+
}
33+
34+
impl From<String> for Value {
35+
fn from(string: String) -> Self {
36+
Value::String(string)
37+
}
38+
}
39+
40+
impl From<&str> for Value {
41+
fn from(string: &str) -> Self {
42+
Value::String(string.to_string())
43+
}
44+
}
45+
46+
macro_rules! impl_value_as_type {
47+
($variant:ident, $typ:ty, $typ_name:expr, false) => {
48+
impl<'a> TryFrom<&'a Value> for &'a $typ {
49+
type Error = Error;
50+
51+
fn try_from(value: &'a Value) -> Result<Self> {
52+
match value {
53+
Value::$variant(v) => Ok(v),
54+
_ => Err(Error::InvalidConversion {
55+
variant: stringify!($variant),
56+
output_type: $typ_name,
57+
}),
58+
}
59+
}
60+
}
61+
62+
impl<'a> TryFrom<&'a mut Value> for &'a mut $typ {
63+
type Error = Error;
64+
65+
fn try_from(value: &'a mut Value) -> Result<Self> {
66+
match value {
67+
Value::$variant(v) => Ok(v),
68+
_ => Err(Error::InvalidConversion {
69+
variant: stringify!($variant),
70+
output_type: $typ_name,
71+
}),
72+
}
73+
}
74+
}
75+
};
76+
77+
($variant:ident, $typ:ty, $typ_name:expr, true) => {
78+
impl_value_as_type!($variant, $typ, $typ_name, false);
79+
80+
impl<'a> TryFrom<&'a mut Value> for $typ {
81+
type Error = Error;
82+
83+
fn try_from(value: &'a mut Value) -> Result<Self> {
84+
match value {
85+
Value::$variant(v) => Ok(*v),
86+
_ => Err(Error::InvalidConversion {
87+
variant: stringify!($variant),
88+
output_type: $typ_name,
89+
}),
90+
}
91+
}
92+
}
93+
};
94+
}
95+
96+
impl_value_as_type!(Float, Float, FLOAT_TYPE, true);
97+
impl_value_as_type!(Int, Int, INT_TYPE, true);
98+
impl_value_as_type!(Bool, bool, "bool", true);
99+
impl_value_as_type!(String, String, "String", false);
100+
impl_value_as_type!(String, str, "str", false);
101+
impl_value_as_type!(Group, Group, "Group", false);
102+
103+
#[derive(Debug, Clone)]
104+
pub struct Entry {
105+
pub name: String,
106+
pub value: Value,
107+
}
108+
109+
#[derive(Debug, Clone)]
110+
pub struct Group {
111+
pub entries: Vec<Entry>,
112+
}
113+
114+
pub trait Accessor {
115+
fn get(&self, key: &[&str]) -> Option<&Value>;
116+
fn get_mut(&mut self, key: &[&str]) -> Option<&mut Value>;
117+
fn get_all(&self, key: &[&str]) -> Vec<&Value>;
118+
fn get_all_mut(&mut self, key: &[&str]) -> Vec<&mut Value>;
119+
}
120+
121+
impl Accessor for Group {
122+
fn get(&self, key: &[&str]) -> Option<&Value> {
123+
if key.is_empty() {
124+
return None;
125+
}
126+
127+
let entry = self.entries.iter().find(|e| e.name == key[0])?;
128+
let remaining_keys = &key[1..];
129+
130+
if remaining_keys.is_empty() {
131+
Some(&entry.value)
132+
} else {
133+
match &entry.value {
134+
Value::Group(group) => group.get(remaining_keys),
135+
_ => None,
136+
}
137+
}
138+
}
139+
140+
fn get_mut(&mut self, key: &[&str]) -> Option<&mut Value> {
141+
if key.is_empty() {
142+
return None;
143+
}
144+
145+
let entry = self.entries.iter_mut().find(|e| e.name == key[0])?;
146+
let remaining_keys = &key[1..];
147+
148+
if remaining_keys.is_empty() {
149+
Some(&mut entry.value)
150+
} else {
151+
match &mut entry.value {
152+
Value::Group(group) => group.get_mut(remaining_keys),
153+
_ => None,
154+
}
155+
}
156+
}
157+
158+
fn get_all(&self, key: &[&str]) -> Vec<&Value> {
159+
let mut v = vec![];
160+
161+
let entries = self.entries.iter().filter(|e| e.name == key[0]);
162+
let remaining_keys = &key[1..];
163+
164+
for entry in entries {
165+
if remaining_keys.is_empty() {
166+
v.push(&entry.value);
167+
} else {
168+
match &entry.value {
169+
Value::Group(group) => v.extend(group.get_all(remaining_keys)),
170+
_ => {}
171+
}
172+
}
173+
}
174+
175+
v
176+
}
177+
178+
fn get_all_mut(&mut self, key: &[&str]) -> Vec<&mut Value> {
179+
let mut v = vec![];
180+
181+
let entries = self.entries.iter_mut().filter(|e| e.name == key[0]);
182+
let remaining_keys = &key[1..];
183+
184+
for entry in entries {
185+
if remaining_keys.is_empty() {
186+
v.push(&mut entry.value);
187+
} else {
188+
match &mut entry.value {
189+
Value::Group(group) => v.extend(group.get_all_mut(remaining_keys)),
190+
_ => {}
191+
}
192+
}
193+
}
194+
195+
v
196+
}
197+
}
198+
199+
#[test]
200+
fn test() {
201+
let mut group = Group {
202+
entries: vec![Entry {
203+
name: "key".to_string(),
204+
value: Group {
205+
entries: vec![Entry {
206+
name: "key".into(),
207+
value: "hello".into(),
208+
}],
209+
}
210+
.into(),
211+
}],
212+
};
213+
214+
let value: &str = group.get(&["key", "key"]).unwrap().try_into().unwrap();
215+
println!("{value:?}");
216+
}

0 commit comments

Comments
 (0)