hocon_rs/
value.rs

1use ahash::{HashMap, HashMapExt};
2use serde::de::{Error, MapAccess, SeqAccess, Visitor};
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4use serde_json::Number;
5use std::collections::BTreeMap;
6use std::collections::hash_map::Entry;
7use std::fmt::{self, Display, Formatter};
8
9use crate::{join, join_format};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum Value {
13    Object(HashMap<String, Value>),
14    Array(Vec<Value>),
15    Boolean(bool),
16    Null,
17    String(String),
18    Number(Number),
19}
20
21impl Value {
22    pub fn object(obj: HashMap<String, Value>) -> Value {
23        Value::Object(obj)
24    }
25
26    pub fn object_from_iter<I>(iter: I) -> Value
27    where
28        I: IntoIterator<Item = (String, Value)>,
29    {
30        Value::Object(HashMap::from_iter(iter))
31    }
32
33    pub fn array(values: Vec<Value>) -> Value {
34        Value::Array(values)
35    }
36
37    pub fn array_from_iter<I>(iter: I) -> Value
38    where
39        I: IntoIterator<Item = Value>,
40    {
41        Value::Array(iter.into_iter().collect())
42    }
43
44    pub fn boolean(boolean: bool) -> Value {
45        Value::Boolean(boolean)
46    }
47
48    pub fn null() -> Value {
49        Value::Null
50    }
51
52    pub fn new_string(string: impl Into<String>) -> Value {
53        Value::String(string.into())
54    }
55}
56
57impl Value {
58    pub fn as_object(&self) -> Option<&HashMap<String, Value>> {
59        match self {
60            Value::Object(object) => Some(object),
61            _ => None,
62        }
63    }
64
65    pub fn as_object_mut(&mut self) -> Option<&mut HashMap<String, Value>> {
66        match self {
67            Value::Object(object) => Some(object),
68            _ => None,
69        }
70    }
71
72    pub fn as_array(&self) -> Option<&Vec<Value>> {
73        match self {
74            Value::Array(array) => Some(array),
75            _ => None,
76        }
77    }
78
79    pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
80        match self {
81            Value::Array(array) => Some(array),
82            _ => None,
83        }
84    }
85
86    pub fn as_boolean(&self) -> Option<bool> {
87        match self {
88            Value::Boolean(boolean) => Some(*boolean),
89            _ => None,
90        }
91    }
92
93    pub fn as_boolean_mut(&mut self) -> Option<&mut bool> {
94        match self {
95            Value::Boolean(boolean) => Some(boolean),
96            _ => None,
97        }
98    }
99
100    pub fn as_str(&self) -> Option<&str> {
101        match self {
102            Value::String(string) => Some(string),
103            _ => None,
104        }
105    }
106
107    pub fn as_str_mut(&mut self) -> Option<&mut String> {
108        match self {
109            Value::String(string) => Some(string),
110            _ => None,
111        }
112    }
113
114    pub fn as_f64(&mut self) -> Option<f64> {
115        match self {
116            Value::Number(number) => number.as_f64(),
117            _ => None,
118        }
119    }
120
121    pub fn as_i64(&self) -> Option<i64> {
122        match self {
123            Value::Number(number) => number.as_i64(),
124            _ => None,
125        }
126    }
127
128    pub fn is_null(&self) -> bool {
129        matches!(self, Value::Null)
130    }
131
132    pub fn ty(&self) -> &'static str {
133        match self {
134            Value::Object(_) => "Object",
135            Value::Array(_) => "Array",
136            Value::Boolean(_) => "Boolean",
137            Value::Null => "Null",
138            Value::String(_) => "String",
139            Value::Number(_) => "Number",
140        }
141    }
142
143    pub fn into_object(self) -> Option<HashMap<String, Value>> {
144        match self {
145            Value::Object(object) => Some(object),
146            _ => None,
147        }
148    }
149
150    pub fn into_array(self) -> Option<Vec<Value>> {
151        match self {
152            Value::Array(array) => Some(array),
153            _ => None,
154        }
155    }
156
157    pub fn into_boolean(self) -> Option<bool> {
158        match self {
159            Value::Boolean(boolean) => Some(boolean),
160            _ => None,
161        }
162    }
163
164    pub fn into_string(self) -> Option<String> {
165        match self {
166            Value::String(string) => Some(string),
167            _ => None,
168        }
169    }
170
171    /// Get value from the given path and returns `None` if it's invalid.
172    ///
173    /// A path is considered invalid if:
174    /// - It is empty
175    /// - Contains leading or trailing `.` or `..` components
176    pub fn get_by_path<'a>(&self, paths: impl AsRef<[&'a str]>) -> Option<&Value> {
177        let paths = paths.as_ref();
178        if paths.is_empty() {
179            return None;
180        }
181        let mut current = self;
182        for &path in paths {
183            if let Value::Object(obj) = current {
184                if let Some(val) = obj.get(path) {
185                    current = val;
186                } else {
187                    return None;
188                }
189            }
190        }
191        Some(current)
192    }
193
194    pub fn get_by_path_mut<'a>(&mut self, paths: impl AsRef<[&'a str]>) -> Option<&mut Value> {
195        let paths = paths.as_ref();
196        if paths.is_empty() {
197            return None;
198        }
199        let mut current = self;
200        for &path in paths {
201            if let Value::Object(obj) = current {
202                if let Some(val) = obj.get_mut(path) {
203                    current = val;
204                } else {
205                    return None;
206                }
207            }
208        }
209        Some(current)
210    }
211
212    /// Merge this `Value` with a fallback `Value`, following HOCON's `withFallback` semantics.
213    ///
214    /// - If both `self` and `fallback` are `Object`s, they are merged key by key:
215    ///   - If a key exists in both objects:
216    ///     - If both values are objects, merge them recursively.
217    ///     - Otherwise, keep the value from `self` (ignore the fallback).
218    ///   - If a key exists only in the fallback, insert it into `self`.
219    /// - For all other cases (non-object values), `self` takes precedence
220    ///   and the fallback is ignored.
221    pub fn with_fallback(self, fallback: Value) -> Value {
222        match (self, fallback) {
223            // Case 1: Both values are objects -> perform deep merge
224            (Value::Object(mut obj), Value::Object(fb_obj)) => {
225                for (k, fb_val) in fb_obj {
226                    match obj.entry(k) {
227                        // If key already exists in `self`
228                        Entry::Occupied(mut occupied_entry) => {
229                            let existing_val = occupied_entry.get_mut();
230
231                            // If both values are objects -> merge recursively
232                            if let (Value::Object(_), Value::Object(_)) = (&existing_val, &fb_val) {
233                                // Temporarily move out the existing value to avoid borrow conflicts
234                                let mut temp = Value::Null;
235                                std::mem::swap(&mut temp, existing_val);
236
237                                // Recursively merge and store back
238                                *existing_val = temp.with_fallback(fb_val);
239                            }
240                            // Otherwise: keep `self`'s value, ignore fallback
241                        }
242
243                        // If key is missing in `self` -> insert fallback value
244                        Entry::Vacant(vacant_entry) => {
245                            vacant_entry.insert(fb_val);
246                        }
247                    }
248                }
249                Value::Object(obj)
250            }
251
252            // Case 2: Non-object values -> always prefer `self`
253            (other, _) => other,
254        }
255    }
256}
257
258impl Value {}
259
260impl Display for Value {
261    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
262        match self {
263            Value::Object(object) => {
264                write!(f, "{{")?;
265                join_format(
266                    object.iter(),
267                    f,
268                    |f| write!(f, ", "),
269                    |f, (k, v)| write!(f, "{k}: {v}"),
270                )?;
271                write!(f, "}}")?;
272                Ok(())
273            }
274            Value::Array(array) => {
275                write!(f, "[")?;
276                join(array.iter(), ", ", f)?;
277                write!(f, "]")?;
278                Ok(())
279            }
280            Value::Boolean(boolean) => {
281                write!(f, "{}", boolean)
282            }
283            Value::Null => {
284                write!(f, "null")
285            }
286            Value::String(string) => {
287                write!(f, "{}", string)
288            }
289            Value::Number(number) => {
290                write!(f, "{}", number)
291            }
292        }
293    }
294}
295
296impl TryFrom<crate::merge::value::Value> for Value {
297    type Error = crate::error::Error;
298
299    fn try_from(value: crate::merge::value::Value) -> Result<Self, Self::Error> {
300        fn from_object(object: crate::merge::object::Object) -> crate::Result<Value> {
301            let inner: BTreeMap<_, _> = object.into();
302            let mut object = HashMap::with_capacity(inner.len());
303            for (k, v) in inner.into_iter() {
304                let v = v.into_inner();
305                if !matches!(v, crate::merge::value::Value::None) {
306                    let v: Value = v.try_into()?;
307                    object.insert(k, v);
308                }
309            }
310            Ok(Value::Object(object))
311        }
312
313        fn from_array(array: crate::merge::array::Array) -> crate::Result<Value> {
314            let mut result = Vec::with_capacity(array.len());
315            for ele in array.into_inner().into_iter() {
316                let v = ele.into_inner();
317                let v: Value = v.try_into()?;
318                result.push(v);
319            }
320            Ok(Value::Array(result))
321        }
322        let value = match value {
323            crate::merge::value::Value::Object(object) => {
324                if object.is_unmerged() {
325                    return Err(crate::error::Error::ResolveIncomplete);
326                }
327                from_object(object)?
328            }
329            crate::merge::value::Value::Array(array) => from_array(array)?,
330            crate::merge::value::Value::Boolean(boolean) => Value::Boolean(boolean),
331            crate::merge::value::Value::Null | crate::merge::value::Value::None => Value::Null,
332            crate::merge::value::Value::String(string) => Value::String(string),
333            crate::merge::value::Value::Number(number) => Value::Number(number),
334            crate::merge::value::Value::Substitution(_)
335            | crate::merge::value::Value::Concat(_)
336            | crate::merge::value::Value::AddAssign(_)
337            | crate::merge::value::Value::DelayReplacement(_) => {
338                return Err(crate::error::Error::ResolveIncomplete);
339            }
340        };
341        Ok(value)
342    }
343}
344
345impl Serialize for Value {
346    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
347    where
348        S: Serializer,
349    {
350        match self {
351            Value::Object(map) => map.serialize(serializer),
352            Value::Array(arr) => arr.serialize(serializer),
353            Value::Boolean(b) => b.serialize(serializer),
354            Value::Null => serializer.serialize_none(),
355            Value::String(s) => s.serialize(serializer),
356            Value::Number(num) => num.serialize(serializer),
357        }
358    }
359}
360
361impl<'de> Deserialize<'de> for Value {
362    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
363    where
364        D: Deserializer<'de>,
365    {
366        struct ValueVisitor;
367
368        impl<'de> Visitor<'de> for ValueVisitor {
369            type Value = Value;
370
371            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
372                formatter.write_str("any valid HOCON value")
373            }
374
375            fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> {
376                Ok(Value::Boolean(v))
377            }
378
379            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> {
380                Ok(Value::Number(Number::from(v)))
381            }
382
383            fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> {
384                Ok(Value::Number(Number::from(v)))
385            }
386
387            fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
388            where
389                E: Error,
390            {
391                Number::from_f64(v)
392                    .map(Value::Number)
393                    .ok_or_else(|| Error::custom("invalid f64 value"))
394            }
395
396            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> {
397                Ok(Value::String(v.to_owned()))
398            }
399
400            fn visit_string<E>(self, v: String) -> Result<Self::Value, E> {
401                Ok(Value::String(v))
402            }
403
404            fn visit_none<E>(self) -> Result<Self::Value, E> {
405                Ok(Value::Null)
406            }
407
408            fn visit_unit<E>(self) -> Result<Self::Value, E> {
409                Ok(Value::Null)
410            }
411
412            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
413            where
414                A: SeqAccess<'de>,
415            {
416                let mut vec = Vec::new();
417                while let Some(elem) = seq.next_element()? {
418                    vec.push(elem);
419                }
420                Ok(Value::Array(vec))
421            }
422
423            fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
424            where
425                M: MapAccess<'de>,
426            {
427                let mut values = HashMap::new();
428                while let Some((k, v)) = map.next_entry()? {
429                    values.insert(k, v);
430                }
431                Ok(Value::Object(values))
432            }
433        }
434
435        deserializer.deserialize_any(ValueVisitor)
436    }
437}