steam_vdf_parser/value/
impls.rs

1//! Trait implementations for VDF types.
2
3use alloc::borrow::Cow;
4use alloc::string::String;
5
6use super::types::{Key, Obj, Value, Vdf};
7use core::fmt;
8use core::fmt::Write as _;
9use core::ops::Index;
10
11// ============================================================================
12// Pretty-print helper functions
13// ============================================================================
14
15/// Write a quoted and escaped string to the formatter.
16///
17/// Escapes special characters: `\n`, `\t`, `\r`, `\\`, `"`
18fn write_quoted_str(f: &mut fmt::Formatter<'_>, s: &str) -> fmt::Result {
19    f.write_char('"')?;
20    for c in s.chars() {
21        match c {
22            '\n' => f.write_str("\\n")?,
23            '\t' => f.write_str("\\t")?,
24            '\r' => f.write_str("\\r")?,
25            '\\' => f.write_str("\\\\")?,
26            '"' => f.write_str("\\\"")?,
27            c => f.write_char(c)?,
28        }
29    }
30    f.write_char('"')
31}
32
33/// Write indentation (tabs) to the formatter.
34fn write_indent(f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
35    for _ in 0..level {
36        f.write_char('\t')?;
37    }
38    Ok(())
39}
40
41/// Helper struct for pretty-printing an Obj with a specific indent level.
42struct PrettyObj<'a, 'text> {
43    obj: &'a Obj<'text>,
44    indent: usize,
45}
46
47impl fmt::Display for PrettyObj<'_, '_> {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        writeln!(f, "{{")?;
50        for (key, value) in self.obj.inner.iter() {
51            write_indent(f, self.indent + 1)?;
52            write_quoted_str(f, key)?;
53            if let Value::Obj(inner_obj) = value {
54                // Object value: key on one line, value (with braces) on next lines
55                writeln!(f)?;
56                write_indent(f, self.indent + 1)?;
57                write!(
58                    f,
59                    "{}",
60                    PrettyObj {
61                        obj: inner_obj,
62                        indent: self.indent + 1
63                    }
64                )?;
65                writeln!(f)?;
66            } else {
67                // Scalar value: key<tab>value on same line
68                write!(f, "\t")?;
69                write!(f, "{:#}", value)?;
70                writeln!(f)?;
71            }
72        }
73        write_indent(f, self.indent)?;
74        write!(f, "}}")
75    }
76}
77
78// ============================================================================
79// From implementations for Value
80// ============================================================================
81
82impl<'text> From<&'text str> for Value<'text> {
83    fn from(s: &'text str) -> Self {
84        Value::Str(Cow::Borrowed(s))
85    }
86}
87
88impl From<String> for Value<'static> {
89    fn from(s: String) -> Self {
90        Value::Str(Cow::Owned(s))
91    }
92}
93
94impl From<i32> for Value<'static> {
95    fn from(n: i32) -> Self {
96        Value::I32(n)
97    }
98}
99
100impl From<u64> for Value<'static> {
101    fn from(n: u64) -> Self {
102        Value::U64(n)
103    }
104}
105
106impl From<f32> for Value<'static> {
107    fn from(n: f32) -> Self {
108        Value::Float(n)
109    }
110}
111
112impl From<u32> for Value<'static> {
113    fn from(n: u32) -> Self {
114        Value::Pointer(n)
115    }
116}
117
118impl From<[u8; 4]> for Value<'static> {
119    fn from(color: [u8; 4]) -> Self {
120        Value::Color(color)
121    }
122}
123
124impl<'text> From<Obj<'text>> for Value<'text> {
125    fn from(obj: Obj<'text>) -> Self {
126        Value::Obj(obj)
127    }
128}
129
130impl<'text> fmt::Display for Value<'text> {
131    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132        match self {
133            Value::Str(s) => write_quoted_str(f, s),
134            Value::Obj(obj) => write!(f, "{}", obj),
135            Value::I32(n) => write!(f, "\"{}\"", n),
136            Value::U64(n) => write!(f, "\"{}\"", n),
137            Value::Float(n) => write!(f, "\"{}\"", n),
138            Value::Pointer(n) => write!(f, "\"0x{:08x}\"", n),
139            Value::Color(c) => write!(f, "\"{} {} {} {}\"", c[0], c[1], c[2], c[3]),
140        }
141    }
142}
143
144impl<'text> Default for Obj<'text> {
145    fn default() -> Self {
146        Self::new()
147    }
148}
149
150impl<'text> fmt::Display for Obj<'text> {
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152        write!(f, "{}", PrettyObj { obj: self, indent: 0 })
153    }
154}
155
156impl<'text> fmt::Display for Vdf<'text> {
157    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158        write_quoted_str(f, self.key())?;
159        writeln!(f)?;
160        write!(f, "{}", self.value())
161    }
162}
163
164// ============================================================================
165// IntoIterator implementations for Obj
166// ============================================================================
167
168impl<'text> IntoIterator for Obj<'text> {
169    type Item = (Key<'text>, Value<'text>);
170    type IntoIter = indexmap::map::IntoIter<Key<'text>, Value<'text>>;
171
172    fn into_iter(self) -> Self::IntoIter {
173        self.inner.into_iter()
174    }
175}
176
177impl<'a, 'text> IntoIterator for &'a Obj<'text> {
178    type Item = (&'a Key<'text>, &'a Value<'text>);
179    type IntoIter = indexmap::map::Iter<'a, Key<'text>, Value<'text>>;
180
181    fn into_iter(self) -> Self::IntoIter {
182        self.inner.iter()
183    }
184}
185
186// ============================================================================
187// Index implementations for Value and Obj
188// ============================================================================
189
190impl<'text> Index<&str> for Value<'text> {
191    type Output = Value<'text>;
192
193    /// Returns a reference to the value at the given key.
194    ///
195    /// # Panics
196    ///
197    /// Panics if this is not an object or if the key doesn't exist.
198    /// Use `get()` for non-panicking access.
199    fn index(&self, key: &str) -> &Self::Output {
200        self.get(key).expect("key not found in Value")
201    }
202}
203
204impl<'text> Index<&str> for Obj<'text> {
205    type Output = Value<'text>;
206
207    /// Returns a reference to the value at the given key.
208    ///
209    /// # Panics
210    ///
211    /// Panics if the key doesn't exist. Use `get()` for non-panicking access.
212    fn index(&self, key: &str) -> &Self::Output {
213        self.get(key).expect("key not found in Obj")
214    }
215}