keyvalues_parser/lib.rs
1#![doc = include_str!("../README.md")]
2#![allow(unknown_lints)]
3#![allow(clippy::result_large_err)]
4// TODO: resolve this ^^
5
6use std::{
7 borrow::Cow,
8 collections::{btree_map::IntoIter, BTreeMap},
9 ops::{Deref, DerefMut},
10};
11
12pub mod error;
13#[cfg(feature = "serde")]
14mod serde;
15pub mod text;
16
17/// A Key is simply an alias for `Cow<str>`
18pub type Key<'text> = Cow<'text, str>;
19
20/// A loosely typed representation of VDF text
21///
22/// `Vdf` is represented as a single [`Key`] mapped to a single [`Value`]
23///
24/// ## Parse
25///
26/// `Vdf`s will generally be created through the use of [`Vdf::parse()`] which takes a string
27/// representing VDF text and attempts to parse it to a `Vdf` representation.
28///
29/// ## Mutate
30///
31/// From there you can manipulate/extract from the representation as desired by using the standard
32/// conventions on the internal types (plain old `BTreeMap`s, `Vec`s, and `Cow`s all the way down)
33///
34/// ## Render
35///
36/// The `Vdf` can also be rendered back to its text form through its `Display` implementation
37///
38/// ## Example
39///
40/// ```
41/// use keyvalues_parser::Vdf;
42///
43/// // Parse
44/// let vdf_text = r#"
45/// "Outer Key"
46/// {
47/// "Inner Key" "Inner Value"
48/// "Inner Key"
49/// {
50/// }
51/// }
52/// "#;
53/// let mut parsed = Vdf::parse(vdf_text)?;
54///
55/// // Mutate: i.e. remove the last "Inner Key" pair
56/// parsed
57/// .value
58/// .get_mut_obj()
59/// .unwrap()
60/// .get_mut("Inner Key")
61/// .unwrap()
62/// .pop();
63///
64/// // Render: prints
65/// // "Outer Key"
66/// // {
67/// // "Inner Key" "Inner Value"
68/// // }
69/// println!("{}", parsed);
70/// # Ok::<(), keyvalues_parser::error::Error>(())
71/// ```
72#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
73pub struct Vdf<'text> {
74 pub key: Key<'text>,
75 pub value: Value<'text>,
76}
77
78impl<'text> From<PartialVdf<'text>> for Vdf<'text> {
79 fn from(partial: PartialVdf<'text>) -> Self {
80 Self {
81 key: partial.key,
82 value: partial.value,
83 }
84 }
85}
86
87// TODO: Just store a `Vdf` internally?
88// TODO: don't expose these publicly?
89#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
90pub struct PartialVdf<'text> {
91 pub key: Key<'text>,
92 pub value: Value<'text>,
93 pub bases: Vec<Cow<'text, str>>,
94}
95
96impl<'text> Vdf<'text> {
97 /// Creates a [`Vdf`] using a provided key and value
98 ///
99 /// ```
100 /// use keyvalues_parser::{Vdf, Value};
101 /// use std::borrow::Cow;
102 ///
103 /// let vdf = Vdf::new(Cow::from("Much Key"), Value::Str(Cow::from("Such Wow")));
104 /// // prints
105 /// // "Much Key" "Such Wow"
106 /// println!("{}", vdf);
107 /// ```
108 pub fn new(key: Key<'text>, value: Value<'text>) -> Self {
109 Self { key, value }
110 }
111}
112
113// TODO: why is this type alias a thing if it's not private but the usage of it inside `Obj` is?
114type ObjInner<'text> = BTreeMap<Key<'text>, Vec<Value<'text>>>;
115type ObjInnerPair<'text> = (Key<'text>, Vec<Value<'text>>);
116
117#[derive(Debug, Clone, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
118pub struct Obj<'text>(pub ObjInner<'text>);
119
120impl<'text> Obj<'text> {
121 /// Creates an empty object value
122 ///
123 /// Internally This is just a [`BTreeMap`] that maps [`Key`]s to a [`Vec`] of [`Value`]s
124 ///
125 /// ```
126 /// # use keyvalues_parser::{Obj, Value};
127 /// # use std::borrow::Cow;
128 /// let mut obj = Obj::new();
129 /// obj.insert(
130 /// Cow::from("key"),
131 /// vec![]
132 /// );
133 /// obj.insert(
134 /// Cow::from("earlier key"),
135 /// vec![Value::Obj(Obj::default())]
136 /// );
137 ///
138 /// // It's a b-tree map so the entries are sorted by keys
139 /// assert_eq!(
140 /// obj.keys().collect::<Vec<_>>(),
141 /// ["earlier key", "key"]
142 /// );
143 /// ```
144 pub fn new() -> Self {
145 Self::default()
146 }
147
148 /// Returns the inner [`BTreeMap`]
149 ///
150 /// ```
151 /// # use keyvalues_parser::{Obj, Value};
152 /// # use std::{borrow::Cow, collections::BTreeMap};
153 /// let mut obj = Obj::new();
154 /// obj.insert(Cow::from("much key"), vec![]);
155 ///
156 /// let inner: BTreeMap<_, _> = obj.into_inner();
157 /// // Prints:
158 /// // {
159 /// // "much key": [],
160 /// // }
161 /// println!("{:#?}", inner);
162 /// ```
163 pub fn into_inner(self) -> ObjInner<'text> {
164 self.0
165 }
166
167 /// Creates an iterator that returns the [`Vdf`]s that compose the object
168 ///
169 /// This is notably different compared to just iterating over the `BTreeMap`s items because it
170 /// will emit a [`Vdf`] for each key-value pair while the actual items are key-values pairs.
171 /// This means that empty values will not emit a [`Vdf`] at all, and a pair that has multiple
172 /// entries in values will emit a [`Vdf`] for each pairing
173 ///
174 /// ```
175 /// # use keyvalues_parser::{Obj, Value, Vdf};
176 /// # use std::borrow::Cow;
177 /// let mut obj = Obj::new();
178 /// obj.insert(
179 /// Cow::from("no values"),
180 /// vec![]
181 /// );
182 /// obj.insert(
183 /// Cow::from("multiple values"),
184 /// vec![Value::Str(Cow::from("first")), Value::Str(Cow::from("second"))]
185 /// );
186 ///
187 /// let vdfs: Vec<_> = obj.into_vdfs().collect();
188 /// assert_eq!(
189 /// vdfs,
190 /// [
191 /// Vdf {
192 /// key: Cow::from("multiple values"),
193 /// value: Value::Str(Cow::from("first"))
194 /// },
195 /// Vdf {
196 /// key: Cow::from("multiple values"),
197 /// value: Value::Str(Cow::from("second"))
198 /// },
199 /// ]
200 /// );
201 /// ```
202 pub fn into_vdfs(self) -> IntoVdfs<'text> {
203 IntoVdfs::new(self)
204 }
205}
206
207impl<'text> FromIterator<ObjInnerPair<'text>> for Obj<'text> {
208 fn from_iter<T: IntoIterator<Item = ObjInnerPair<'text>>>(iter: T) -> Self {
209 let mut inner = BTreeMap::new();
210 for (key, values) in iter {
211 inner.insert(key, values);
212 }
213
214 Self(inner)
215 }
216}
217
218impl<'text> Deref for Obj<'text> {
219 type Target = ObjInner<'text>;
220
221 fn deref(&self) -> &Self::Target {
222 &self.0
223 }
224}
225
226impl DerefMut for Obj<'_> {
227 fn deref_mut(&mut self) -> &mut Self::Target {
228 &mut self.0
229 }
230}
231
232/// An iterator over an [`Obj`]'s [`Vdf`] pairs
233///
234/// Typically created by calling [`Obj::into_vdfs`] on an existing object
235pub struct IntoVdfs<'text> {
236 // TODO: can this just store an iterator for the values instead of `.collect()`ing
237 current_entry: Option<ObjInnerPair<'text>>,
238 it: IntoIter<Key<'text>, Vec<Value<'text>>>,
239}
240
241impl<'text> IntoVdfs<'text> {
242 fn new(obj: Obj<'text>) -> Self {
243 Self {
244 current_entry: None,
245 it: obj.into_inner().into_iter(),
246 }
247 }
248}
249
250impl<'text> Iterator for IntoVdfs<'text> {
251 type Item = Vdf<'text>;
252
253 fn next(&mut self) -> Option<Self::Item> {
254 // Iteration will pop the first pair off `current_entry` if it's set and then falls back to
255 // reading in a new `current_entry` from `it`. If `it` is exhausted then we're done
256 loop {
257 match self.current_entry.take() {
258 // There is a pair to return
259 Some((key, mut values)) if !values.is_empty() => {
260 let value = values.pop().expect("values isn't empty");
261 self.current_entry = Some((key.clone(), values));
262 return Some(Vdf::new(key, value));
263 }
264 _ => {
265 let (key, values) = self.it.next()?;
266 // Store the next entry. Flip the values so that `pop`ing returns correct order
267 self.current_entry = Some((key, values.into_iter().rev().collect()));
268 }
269 }
270 }
271 }
272}
273
274// TODO: custom Debug that's more succinct
275/// Enum representing all valid VDF values
276///
277/// VDF is composed of [`Key`]s and their respective [`Value`]s where this represents the latter. A
278/// value is either going to be a `Str(Cow<str>)`, or an `Obj(Obj)` that contains a list of keys
279/// and values.
280///
281/// ```
282/// # use keyvalues_parser::{Obj, Value};
283/// # use std::borrow::Cow;
284/// let value_str = Value::Str(Cow::from("some text"));
285/// let value_obj = Value::Obj(Obj::new());
286/// ```
287#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
288pub enum Value<'text> {
289 Str(Cow<'text, str>),
290 Obj(Obj<'text>),
291}
292
293impl<'text> Value<'text> {
294 /// Returns if the current value is the `Str` variant
295 ///
296 /// ```
297 /// use std::borrow::Cow;
298 /// use keyvalues_parser::{Obj, Value};
299 ///
300 /// let value_str = Value::Str(Cow::default());
301 /// assert!(value_str.is_str());
302 /// ```
303 pub fn is_str(&self) -> bool {
304 self.get_str().is_some()
305 }
306
307 /// Returns if the current value is the `Obj` variant
308 ///
309 /// ```
310 /// use keyvalues_parser::{Obj, Value};
311 ///
312 /// let value_obj = Value::Obj(Obj::default());
313 /// assert!(value_obj.is_obj());
314 /// ```
315 pub fn is_obj(&self) -> bool {
316 self.get_obj().is_some()
317 }
318
319 /// Gets the inner `&str` if this is a `Value::Str`
320 ///
321 /// ```
322 /// # use keyvalues_parser::Value;
323 /// # use std::borrow::Cow;
324 /// let value = Value::Str(Cow::from("some text"));
325 ///
326 /// if let Some(s) = value.get_str() {
327 /// println!("value str: {}", s);
328 /// }
329 /// ```
330 pub fn get_str(&self) -> Option<&str> {
331 if let Self::Str(s) = self {
332 Some(s)
333 } else {
334 None
335 }
336 }
337
338 /// Gets the inner `&Obj` if this value is a `Value::Obj`
339 ///
340 /// ```
341 /// # use keyvalues_parser::{Obj, Value};
342 /// let value = Value::Obj(Obj::new());
343 ///
344 /// if let Some(obj) = value.get_obj() {
345 /// println!("value obj: {:?}", obj);
346 /// }
347 /// ```
348 pub fn get_obj(&self) -> Option<&Obj<'_>> {
349 if let Self::Obj(obj) = self {
350 Some(obj)
351 } else {
352 None
353 }
354 }
355
356 /// Gets the inner `&mut str` if this is a `Value::Str`
357 ///
358 /// ```
359 /// # use keyvalues_parser::Value;
360 /// # use std::borrow::Cow;
361 /// let mut value = Value::Str(Cow::from("some text"));
362 /// let mut inner_str = value.get_mut_str().unwrap();
363 /// inner_str.to_mut().make_ascii_uppercase();
364 ///
365 /// assert_eq!(
366 /// value,
367 /// Value::Str(Cow::from("SOME TEXT"))
368 /// );
369 /// ```
370 pub fn get_mut_str(&mut self) -> Option<&mut Cow<'text, str>> {
371 if let Self::Str(s) = self {
372 Some(s)
373 } else {
374 None
375 }
376 }
377
378 /// Gets the inner `&mut Obj` if this is a `Value::Obj`
379 ///
380 /// ```
381 /// # use keyvalues_parser::{Obj, Value};
382 /// # use std::borrow::Cow;
383 /// let mut value = Value::Obj(Obj::new());
384 /// let mut inner_obj = value.get_mut_obj().unwrap();
385 /// inner_obj.insert(Cow::from("new key"), vec![]);
386 ///
387 /// // Prints:
388 /// // Value::Obj({
389 /// // "new key": [],
390 /// // })
391 /// println!("{:?}", value);
392 /// ```
393 pub fn get_mut_obj(&mut self) -> Option<&mut Obj<'text>> {
394 if let Self::Obj(obj) = self {
395 Some(obj)
396 } else {
397 None
398 }
399 }
400
401 /// Unwraps the `Cow<str>` from the `Value::Str`
402 ///
403 /// # Panics
404 ///
405 /// If the variant was `Value::Obj`
406 ///
407 /// # Examples
408 ///
409 /// ```
410 /// use keyvalues_parser::Value;
411 /// use std::borrow::Cow;
412 ///
413 /// let value = Value::Str(Cow::from("Sample text"));
414 /// assert_eq!(value.unwrap_str(), "Sample text");
415 /// ```
416 ///
417 /// ```should_panic
418 /// use keyvalues_parser::{Value, Obj};
419 ///
420 /// let value = Value::Obj(Obj::new());
421 /// value.unwrap_str(); // <-- panics
422 /// ```
423 pub fn unwrap_str(self) -> Cow<'text, str> {
424 self.expect_str("Called `unwrap_str` on a `Value::Obj` variant")
425 }
426
427 /// Unwraps the [`Obj`] from the `Value::Obj`
428 ///
429 /// # Panics
430 ///
431 /// If the variant was `Value::Str`
432 ///
433 /// # Examples
434 ///
435 /// ```
436 /// use keyvalues_parser::{Obj, Value};
437 ///
438 /// let value = Value::Obj(Obj::new());
439 /// assert_eq!(value.unwrap_obj(), Obj::new());
440 /// ```
441 ///
442 /// ```should_panic
443 /// use keyvalues_parser::Value;
444 /// use std::borrow::Cow;
445 ///
446 /// let value = Value::Str(Cow::from("D'Oh"));
447 /// value.unwrap_obj(); // <-- panics
448 /// ```
449 pub fn unwrap_obj(self) -> Obj<'text> {
450 self.expect_obj("Called `unwrap_obj` on a `Value::Str` variant")
451 }
452
453 /// Refer to [Value::unwrap_str]. Same situation, but with a custom message
454 pub fn expect_str(self, msg: &str) -> Cow<'text, str> {
455 if let Self::Str(s) = self {
456 s
457 } else {
458 panic!("{}", msg)
459 }
460 }
461
462 /// Refer to [Value::unwrap_obj]. Same situation, but with a custom message
463 pub fn expect_obj(self, msg: &str) -> Obj<'text> {
464 if let Self::Obj(obj) = self {
465 obj
466 } else {
467 panic!("{}", msg)
468 }
469 }
470}