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}