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