Skip to main content

libconfig/
value.rs

1//! A dynamically-typed representation of libconfig data
2//!
3//! This module provides the `Value` enum which represents any valid libconfig value.
4//! It can be used when you don't know the structure of the data at compile time.
5
6use crate::de::is_list_context;
7use crate::error::{Error, Result};
8use indexmap::IndexMap;
9use serde::de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor};
10use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
11use std::fmt;
12use std::ops::Index;
13
14/// A dynamically-typed value that can represent any libconfig data
15///
16/// # Examples
17///
18/// ```
19/// use libconfig::Value;
20///
21/// let config = r#"
22///     {
23///         name = "My App";
24///         version = 1;
25///         enabled = true;
26///         ports = [8080, 8081, 8082];
27///     }
28/// "#;
29///
30/// let v = Value::from_str(config).unwrap();
31///
32/// assert_eq!(v["name"], "My App");
33/// assert_eq!(v["version"], 1);
34/// assert_eq!(v["enabled"], true);
35/// assert_eq!(v["ports"][0], 8080);
36/// ```
37#[derive(Debug, Clone, PartialEq)]
38pub enum Value {
39    /// Represents a boolean value
40    Bool(bool),
41
42    /// Represents a 32-bit integer
43    Integer(i32),
44
45    /// Represents a 64-bit integer
46    Integer64(i64),
47
48    /// Represents a floating point number
49    Float(f64),
50
51    /// Represents a string
52    String(String),
53
54    /// Represents an array (homogeneous sequence)
55    Array(Vec<Value>),
56
57    /// Represents a list (heterogeneous sequence)
58    List(Vec<Value>),
59
60    /// Represents a group (object/map)
61    Group(Map),
62}
63
64/// A map of string keys to `Value`s, representing a libconfig group
65/// Uses IndexMap to preserve insertion order
66pub type Map = IndexMap<String, Value>;
67
68/// A single segment of a libconfig path.
69#[derive(Debug, Clone, PartialEq)]
70enum PathSegment<'a> {
71    /// A named key for indexing into a Group
72    Key(&'a str),
73    /// A numeric index for indexing into an Array or List
74    Index(usize),
75}
76
77/// Parses a libconfig path string into a sequence of segments.
78///
79/// Supports:
80///   - Dot-separated keys: `"application.window.title"`
81///   - Bracket indices: `"items.[0].title"` (libconfig spec)
82///   - Bare numeric indices: `"items.0"` (backward compat)
83///
84/// Returns `None` if the path is empty or contains malformed segments.
85fn parse_path(path: &str) -> Option<Vec<PathSegment<'_>>> {
86    if path.is_empty() {
87        return None;
88    }
89
90    let mut segments = Vec::new();
91    for part in path.split('.') {
92        if part.is_empty() {
93            return None;
94        }
95
96        if part.starts_with('[') && part.ends_with(']') {
97            let inner = &part[1..part.len() - 1];
98            let index: usize = inner.parse().ok()?;
99            segments.push(PathSegment::Index(index));
100        } else if let Ok(index) = part.parse::<usize>() {
101            segments.push(PathSegment::Index(index));
102        } else {
103            segments.push(PathSegment::Key(part));
104        }
105    }
106
107    if segments.is_empty() {
108        None
109    } else {
110        Some(segments)
111    }
112}
113
114impl Value {
115    /// Returns true if the value is a boolean
116    pub fn is_bool(&self) -> bool {
117        matches!(self, Value::Bool(_))
118    }
119
120    /// Returns true if the value is an integer (32-bit or 64-bit)
121    pub fn is_integer(&self) -> bool {
122        matches!(self, Value::Integer(_) | Value::Integer64(_))
123    }
124
125    /// Returns true if the value is a 32-bit integer
126    pub fn is_i32(&self) -> bool {
127        matches!(self, Value::Integer(_))
128    }
129
130    /// Returns true if the value is a 64-bit integer
131    pub fn is_i64(&self) -> bool {
132        matches!(self, Value::Integer64(_))
133    }
134
135    /// Returns true if the value is a float
136    pub fn is_float(&self) -> bool {
137        matches!(self, Value::Float(_))
138    }
139
140    /// Returns true if the value is a number (integer or float)
141    pub fn is_number(&self) -> bool {
142        matches!(
143            self,
144            Value::Integer(_) | Value::Integer64(_) | Value::Float(_)
145        )
146    }
147
148    /// Returns true if the value is a string
149    pub fn is_string(&self) -> bool {
150        matches!(self, Value::String(_))
151    }
152
153    /// Returns true if the value is an array
154    pub fn is_array(&self) -> bool {
155        matches!(self, Value::Array(_))
156    }
157
158    /// Returns true if the value is a list
159    pub fn is_list(&self) -> bool {
160        matches!(self, Value::List(_))
161    }
162
163    /// Returns true if the value is a group (object)
164    pub fn is_group(&self) -> bool {
165        matches!(self, Value::Group(_))
166    }
167
168    /// If the value is a boolean, returns it. Returns None otherwise.
169    pub fn as_bool(&self) -> Option<bool> {
170        match self {
171            Value::Bool(b) => Some(*b),
172            _ => None,
173        }
174    }
175
176    /// If the value is an integer, returns it as i32. Returns None otherwise.
177    pub fn as_i32(&self) -> Option<i32> {
178        match self {
179            Value::Integer(i) => Some(*i),
180            Value::Integer64(i) if *i >= i32::MIN as i64 && *i <= i32::MAX as i64 => {
181                Some(*i as i32)
182            }
183            _ => None,
184        }
185    }
186
187    /// If the value is an integer, returns it as i64. Returns None otherwise.
188    pub fn as_i64(&self) -> Option<i64> {
189        match self {
190            Value::Integer(i) => Some(*i as i64),
191            Value::Integer64(i) => Some(*i),
192            _ => None,
193        }
194    }
195
196    /// If the value is a float, returns it. Returns None otherwise.
197    pub fn as_f64(&self) -> Option<f64> {
198        match self {
199            Value::Float(f) => Some(*f),
200            Value::Integer(i) => Some(*i as f64),
201            Value::Integer64(i) => Some(*i as f64),
202            _ => None,
203        }
204    }
205
206    /// If the value is a string, returns a reference to it. Returns None otherwise.
207    pub fn as_str(&self) -> Option<&str> {
208        match self {
209            Value::String(s) => Some(s),
210            _ => None,
211        }
212    }
213
214    /// If the value is an array or list, returns a reference to it. Returns None otherwise.
215    pub fn as_array(&self) -> Option<&Vec<Value>> {
216        match self {
217            Value::Array(arr) | Value::List(arr) => Some(arr),
218            _ => None,
219        }
220    }
221
222    /// If the value is a group, returns a reference to the map. Returns None otherwise.
223    pub fn as_group(&self) -> Option<&Map> {
224        match self {
225            Value::Group(map) => Some(map),
226            _ => None,
227        }
228    }
229
230    /// Gets a reference to a value in a group by key
231    ///
232    /// Returns None if the value is not a group or the key doesn't exist.
233    pub fn get<S: AsRef<str>>(&self, key: S) -> Option<&Value> {
234        match self {
235            Value::Group(map) => map.get(key.as_ref()),
236            _ => None,
237        }
238    }
239
240    /// Gets a mutable reference to a value in a group by key
241    ///
242    /// Returns None if the value is not a group or the key doesn't exist.
243    pub fn get_mut<S: AsRef<str>>(&mut self, key: S) -> Option<&mut Value> {
244        match self {
245            Value::Group(map) => map.get_mut(key.as_ref()),
246            _ => None,
247        }
248    }
249
250    /// Gets a reference to a value in an array/list by index
251    ///
252    /// Returns None if the value is not an array/list or the index is out of bounds.
253    pub fn get_index(&self, index: usize) -> Option<&Value> {
254        match self {
255            Value::Array(arr) | Value::List(arr) => arr.get(index),
256            _ => None,
257        }
258    }
259
260    /// Looks up a value by a dotted path like "application.window.title"
261    ///
262    /// Returns None if any part of the path doesn't exist.
263    ///
264    /// # Examples
265    ///
266    /// ```
267    /// use libconfig::Value;
268    ///
269    /// let config = r#"
270    ///     {
271    ///         application = {
272    ///             window = {
273    ///                 title = "My App";
274    ///             };
275    ///         };
276    ///     }
277    /// "#;
278    ///
279    /// let v = Value::from_str(config).unwrap();
280    /// assert_eq!(v.lookup("application.window.title").and_then(|v| v.as_str()), Some("My App"));
281    /// ```
282    pub fn lookup(&self, path: &str) -> Option<&Value> {
283        let segments = parse_path(path)?;
284        let mut current = self;
285        for segment in &segments {
286            match segment {
287                PathSegment::Key(key) => current = current.get(*key)?,
288                PathSegment::Index(index) => current = current.get_index(*index)?,
289            }
290        }
291        Some(current)
292    }
293
294    /// Looks up a mutable reference to a value by a dotted path like "application.window.title"
295    ///
296    /// Returns None if any part of the path doesn't exist.
297    /// Supports both bracket notation (`items.[0]`) and bare numeric (`items.0`).
298    ///
299    /// # Examples
300    ///
301    /// ```
302    /// use libconfig::Value;
303    ///
304    /// let config = r#"
305    ///     {
306    ///         ports = [80, 443];
307    ///     }
308    /// "#;
309    ///
310    /// let mut v = Value::from_str(config).unwrap();
311    /// *v.lookup_mut("ports.[0]").unwrap() = Value::Integer(8080);
312    /// assert_eq!(v["ports.0"], 8080);
313    /// ```
314    pub fn lookup_mut(&mut self, path: &str) -> Option<&mut Value> {
315        let segments = parse_path(path)?;
316        let mut current = self;
317        for segment in &segments {
318            match segment {
319                PathSegment::Key(key) => match current {
320                    Value::Group(map) => current = map.get_mut(*key)?,
321                    _ => return None,
322                },
323                PathSegment::Index(index) => match current {
324                    Value::Array(arr) | Value::List(arr) => current = arr.get_mut(*index)?,
325                    _ => return None,
326                },
327            }
328        }
329        Some(current)
330    }
331
332    /// Sets a value at the given path, creating intermediate `Group` nodes as needed.
333    ///
334    /// Returns `Some(())` on success, or `None` if the path is invalid or an
335    /// intermediate value is not a Group/Array/List.
336    ///
337    /// Array/list indices must refer to existing elements (no auto-extension).
338    ///
339    /// # Examples
340    ///
341    /// ```
342    /// use libconfig::Value;
343    /// use indexmap::IndexMap;
344    ///
345    /// let mut v = Value::Group(IndexMap::new());
346    /// v.set("a.b.c", Value::Integer(42));
347    /// assert_eq!(v.lookup("a.b.c").unwrap().as_i32(), Some(42));
348    /// ```
349    pub fn set(&mut self, path: &str, value: Value) -> Option<()> {
350        let segments = parse_path(path)?;
351        if segments.is_empty() {
352            return None;
353        }
354
355        let mut current = self;
356
357        // Navigate to the parent, creating intermediate Groups as needed
358        for segment in &segments[..segments.len() - 1] {
359            match segment {
360                PathSegment::Key(key) => match current {
361                    Value::Group(map) => {
362                        current = map
363                            .entry(key.to_string())
364                            .or_insert_with(|| Value::Group(IndexMap::new()));
365                    }
366                    _ => return None,
367                },
368                PathSegment::Index(index) => match current {
369                    Value::Array(arr) | Value::List(arr) => {
370                        current = arr.get_mut(*index)?;
371                    }
372                    _ => return None,
373                },
374            }
375        }
376
377        // Apply the final segment
378        match segments.last().unwrap() {
379            PathSegment::Key(key) => match current {
380                Value::Group(map) => {
381                    map.insert(key.to_string(), value);
382                    Some(())
383                }
384                _ => None,
385            },
386            PathSegment::Index(index) => match current {
387                Value::Array(arr) | Value::List(arr) => {
388                    if *index < arr.len() {
389                        arr[*index] = value;
390                        Some(())
391                    } else {
392                        None
393                    }
394                }
395                _ => None,
396            },
397        }
398    }
399
400    /// Removes a value at the given path and returns it.
401    ///
402    /// For group members, the key-value pair is removed.
403    /// For array/list elements, the element is removed and subsequent elements shift down.
404    ///
405    /// Returns `None` if the path is invalid or the target doesn't exist.
406    ///
407    /// # Examples
408    ///
409    /// ```
410    /// use libconfig::Value;
411    ///
412    /// let mut v = Value::from_str(r#"{ a = 1; b = 2; c = 3; }"#).unwrap();
413    /// let removed = v.remove("b");
414    /// assert_eq!(removed, Some(Value::Integer(2)));
415    /// assert!(v.lookup("b").is_none());
416    /// ```
417    pub fn remove(&mut self, path: &str) -> Option<Value> {
418        let segments = parse_path(path)?;
419        if segments.is_empty() {
420            return None;
421        }
422
423        let mut current = self;
424
425        // Navigate to the parent
426        for segment in &segments[..segments.len() - 1] {
427            match segment {
428                PathSegment::Key(key) => match current {
429                    Value::Group(map) => current = map.get_mut(*key)?,
430                    _ => return None,
431                },
432                PathSegment::Index(index) => match current {
433                    Value::Array(arr) | Value::List(arr) => current = arr.get_mut(*index)?,
434                    _ => return None,
435                },
436            }
437        }
438
439        // Remove at the final segment
440        match segments.last().unwrap() {
441            PathSegment::Key(key) => match current {
442                Value::Group(map) => map.shift_remove(*key),
443                _ => None,
444            },
445            PathSegment::Index(index) => match current {
446                Value::Array(arr) | Value::List(arr) => {
447                    if *index < arr.len() {
448                        Some(arr.remove(*index))
449                    } else {
450                        None
451                    }
452                }
453                _ => None,
454            },
455        }
456    }
457
458    /// Parse a libconfig string into a `Value`.
459    ///
460    /// # Examples
461    ///
462    /// ```
463    /// use libconfig::Value;
464    ///
465    /// let v = Value::from_str("{ name = \"test\"; version = 1; }").unwrap();
466    /// assert_eq!(v["name"], "test");
467    /// assert_eq!(v["version"], 1);
468    /// ```
469    pub fn from_str(s: &str) -> Result<Value> {
470        crate::from_str(s)
471    }
472
473    /// Serialize this value to a libconfig string.
474    ///
475    /// The output always wraps top-level groups in braces. For implicit
476    /// (no braces) output, use [`Config::from`] or [`Config::from_str`].
477    ///
478    /// # Examples
479    ///
480    /// ```
481    /// use libconfig::Value;
482    ///
483    /// let v = Value::Integer(42);
484    /// assert_eq!(v.to_string().unwrap(), "42");
485    /// ```
486    pub fn to_string(&self) -> Result<String> {
487        crate::to_string(self)
488    }
489}
490
491// Implement Index for convenient access with []
492// Supports dotted path notation (e.g., value["misc.location"])
493impl Index<&str> for Value {
494    type Output = Value;
495
496    fn index(&self, key: &str) -> &Self::Output {
497        self.lookup(key).expect("key not found in group")
498    }
499}
500
501impl Index<usize> for Value {
502    type Output = Value;
503
504    fn index(&self, index: usize) -> &Self::Output {
505        self.get_index(index).expect("index out of bounds")
506    }
507}
508
509// Implement PartialEq for comparing with native types
510impl PartialEq<bool> for Value {
511    fn eq(&self, other: &bool) -> bool {
512        self.as_bool() == Some(*other)
513    }
514}
515
516impl PartialEq<i32> for Value {
517    fn eq(&self, other: &i32) -> bool {
518        self.as_i32() == Some(*other)
519    }
520}
521
522impl PartialEq<i64> for Value {
523    fn eq(&self, other: &i64) -> bool {
524        self.as_i64() == Some(*other)
525    }
526}
527
528impl PartialEq<f64> for Value {
529    fn eq(&self, other: &f64) -> bool {
530        self.as_f64() == Some(*other)
531    }
532}
533
534impl PartialEq<str> for Value {
535    fn eq(&self, other: &str) -> bool {
536        self.as_str() == Some(other)
537    }
538}
539
540impl PartialEq<&str> for Value {
541    fn eq(&self, other: &&str) -> bool {
542        self.as_str() == Some(*other)
543    }
544}
545
546impl PartialEq<String> for Value {
547    fn eq(&self, other: &String) -> bool {
548        self.as_str() == Some(other.as_str())
549    }
550}
551
552// Implement Display for pretty printing
553impl fmt::Display for Value {
554    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
555        match self {
556            Value::Bool(b) => write!(f, "{}", b),
557            Value::Integer(i) => write!(f, "{}", i),
558            Value::Integer64(i) => write!(f, "{}L", i),
559            Value::Float(fl) => write!(f, "{}", fl),
560            Value::String(s) => write!(f, "\"{}\"", s),
561            Value::Array(arr) => {
562                write!(f, "[")?;
563                for (i, v) in arr.iter().enumerate() {
564                    if i > 0 {
565                        write!(f, ", ")?;
566                    }
567                    write!(f, "{}", v)?;
568                }
569                write!(f, "]")
570            }
571            Value::List(arr) => {
572                write!(f, "(")?;
573                for (i, v) in arr.iter().enumerate() {
574                    if i > 0 {
575                        write!(f, ", ")?;
576                    }
577                    write!(f, "{}", v)?;
578                }
579                write!(f, ")")
580            }
581            Value::Group(map) => {
582                write!(f, "{{")?;
583                for (i, (k, v)) in map.iter().enumerate() {
584                    if i > 0 {
585                        write!(f, ", ")?;
586                    }
587                    write!(f, "{}: {}", k, v)?;
588                }
589                write!(f, "}}")
590            }
591        }
592    }
593}
594
595// Implement Serialize for Value
596impl Serialize for Value {
597    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
598    where
599        S: Serializer,
600    {
601        match self {
602            Value::Bool(b) => serializer.serialize_bool(*b),
603            Value::Integer(i) => serializer.serialize_i32(*i),
604            Value::Integer64(i) => serializer.serialize_i64(*i),
605            Value::Float(f) => serializer.serialize_f64(*f),
606            Value::String(s) => serializer.serialize_str(s),
607            Value::Array(arr) => {
608                let mut seq = serializer.serialize_seq(Some(arr.len()))?;
609                for element in arr {
610                    seq.serialize_element(element)?;
611                }
612                seq.end()
613            }
614            Value::List(arr) => {
615                use serde::ser::SerializeTuple;
616                let mut tup = serializer.serialize_tuple(arr.len())?;
617                for element in arr {
618                    tup.serialize_element(element)?;
619                }
620                tup.end()
621            }
622            Value::Group(map) => {
623                let mut map_ser = serializer.serialize_map(Some(map.len()))?;
624                for (k, v) in map {
625                    map_ser.serialize_entry(k, v)?;
626                }
627                map_ser.end()
628            }
629        }
630    }
631}
632
633// Implement Deserialize for Value
634impl<'de> Deserialize<'de> for Value {
635    fn deserialize<D>(deserializer: D) -> std::result::Result<Value, D::Error>
636    where
637        D: Deserializer<'de>,
638    {
639        deserializer.deserialize_any(ValueVisitor)
640    }
641}
642
643struct ValueVisitor;
644
645impl<'de> Visitor<'de> for ValueVisitor {
646    type Value = Value;
647
648    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
649        formatter.write_str("any valid libconfig value")
650    }
651
652    fn visit_bool<E>(self, value: bool) -> std::result::Result<Value, E>
653    where
654        E: de::Error,
655    {
656        Ok(Value::Bool(value))
657    }
658
659    fn visit_i8<E>(self, value: i8) -> std::result::Result<Value, E>
660    where
661        E: de::Error,
662    {
663        Ok(Value::Integer(value as i32))
664    }
665
666    fn visit_i16<E>(self, value: i16) -> std::result::Result<Value, E>
667    where
668        E: de::Error,
669    {
670        Ok(Value::Integer(value as i32))
671    }
672
673    fn visit_i32<E>(self, value: i32) -> std::result::Result<Value, E>
674    where
675        E: de::Error,
676    {
677        Ok(Value::Integer(value))
678    }
679
680    fn visit_i64<E>(self, value: i64) -> std::result::Result<Value, E>
681    where
682        E: de::Error,
683    {
684        Ok(Value::Integer64(value))
685    }
686
687    fn visit_u8<E>(self, value: u8) -> std::result::Result<Value, E>
688    where
689        E: de::Error,
690    {
691        Ok(Value::Integer(value as i32))
692    }
693
694    fn visit_u16<E>(self, value: u16) -> std::result::Result<Value, E>
695    where
696        E: de::Error,
697    {
698        Ok(Value::Integer(value as i32))
699    }
700
701    fn visit_u32<E>(self, value: u32) -> std::result::Result<Value, E>
702    where
703        E: de::Error,
704    {
705        if value <= i32::MAX as u32 {
706            Ok(Value::Integer(value as i32))
707        } else {
708            Ok(Value::Integer64(value as i64))
709        }
710    }
711
712    fn visit_u64<E>(self, value: u64) -> std::result::Result<Value, E>
713    where
714        E: de::Error,
715    {
716        if value <= i32::MAX as u64 {
717            Ok(Value::Integer(value as i32))
718        } else {
719            Ok(Value::Integer64(value as i64))
720        }
721    }
722
723    fn visit_f32<E>(self, value: f32) -> std::result::Result<Value, E>
724    where
725        E: de::Error,
726    {
727        Ok(Value::Float(value as f64))
728    }
729
730    fn visit_f64<E>(self, value: f64) -> std::result::Result<Value, E>
731    where
732        E: de::Error,
733    {
734        Ok(Value::Float(value))
735    }
736
737    fn visit_str<E>(self, value: &str) -> std::result::Result<Value, E>
738    where
739        E: de::Error,
740    {
741        Ok(Value::String(value.to_string()))
742    }
743
744    fn visit_borrowed_str<E>(self, value: &'de str) -> std::result::Result<Value, E>
745    where
746        E: de::Error,
747    {
748        Ok(Value::String(value.to_string()))
749    }
750
751    fn visit_string<E>(self, value: String) -> std::result::Result<Value, E>
752    where
753        E: de::Error,
754    {
755        Ok(Value::String(value))
756    }
757
758    fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Value, A::Error>
759    where
760        A: SeqAccess<'de>,
761    {
762        let is_list = is_list_context();
763        let mut values = Vec::new();
764        while let Some(value) = seq.next_element()? {
765            values.push(value);
766        }
767        if is_list {
768            Ok(Value::List(values))
769        } else {
770            Ok(Value::Array(values))
771        }
772    }
773
774    fn visit_map<A>(self, mut map: A) -> std::result::Result<Value, A::Error>
775    where
776        A: MapAccess<'de>,
777    {
778        let mut values = Map::new();
779        while let Some((key, value)) = map.next_entry()? {
780            values.insert(key, value);
781        }
782        Ok(Value::Group(values))
783    }
784}
785
786/// Convert a `Value` to a specific type `T`
787///
788/// # Examples
789///
790/// ```
791/// use libconfig::Value;
792///
793/// let v = Value::from_str("42").unwrap();
794/// let num: i32 = libconfig::from_value(v).unwrap();
795/// assert_eq!(num, 42);
796/// ```
797pub fn from_value<T>(value: Value) -> Result<T>
798where
799    T: de::DeserializeOwned,
800{
801    T::deserialize(value).map_err(|e| Error::Message(format!("failed to deserialize: {}", e)))
802}
803
804/// Internal implementation with indentation tracking
805fn to_string_format_impl(value: &Value, indent_level: usize, is_nested: bool) -> Result<String> {
806    const INDENT_SIZE: usize = 2;
807
808    match value {
809        Value::Bool(b) => Ok(if *b {
810            "true".to_string()
811        } else {
812            "false".to_string()
813        }),
814        Value::Integer(i) => Ok(i.to_string()),
815        Value::Integer64(i) => Ok(format!("{}L", i)),
816        Value::Float(f) => {
817            let s = f.to_string();
818            if !s.contains('.') && !s.contains('e') && !s.contains('E') {
819                Ok(format!("{}.0", s))
820            } else {
821                Ok(s)
822            }
823        }
824        Value::String(s) => {
825            let mut result = String::from("\"");
826            for ch in s.chars() {
827                match ch {
828                    '"' => result.push_str("\\\""),
829                    '\\' => result.push_str("\\\\"),
830                    '\n' => result.push_str("\\n"),
831                    '\r' => result.push_str("\\r"),
832                    '\t' => result.push_str("\\t"),
833                    '\x0C' => result.push_str("\\f"),
834                    '\x08' => result.push_str("\\b"),
835                    '\x0B' => result.push_str("\\v"),
836                    '\x07' => result.push_str("\\a"),
837                    _ => result.push(ch),
838                }
839            }
840            result.push('"');
841            Ok(result)
842        }
843        Value::Array(arr) => {
844            let mut result = String::from("[");
845            for (i, elem) in arr.iter().enumerate() {
846                if i > 0 {
847                    result.push_str(", ");
848                }
849                result.push_str(&to_string_format_impl(elem, indent_level, true)?);
850            }
851            result.push(']');
852            Ok(result)
853        }
854        Value::List(arr) => {
855            let mut result = String::from("(");
856            for (i, elem) in arr.iter().enumerate() {
857                if i > 0 {
858                    result.push_str(", ");
859                }
860                result.push_str(&to_string_format_impl(elem, indent_level, true)?);
861            }
862            result.push(')');
863            Ok(result)
864        }
865        Value::Group(map) => {
866            if !is_nested {
867                let mut output = String::new();
868                let mut first = true;
869                for (key, val) in map {
870                    if !first {
871                        output.push(';');
872                        output.push('\n');
873                    }
874                    first = false;
875                    output.push_str(key);
876                    output.push_str(" = ");
877                    let val_str = to_string_format_impl(val, indent_level, true)?;
878                    output.push_str(&val_str);
879                }
880                if !output.is_empty() {
881                    output.push(';');
882                }
883                Ok(output)
884            } else {
885                // Explicit groups or nested groups always have braces
886                let mut output = String::from("{");
887                let next_indent = indent_level + 1;
888                let indent_str = " ".repeat(next_indent * INDENT_SIZE);
889
890                let mut first = true;
891                for (key, val) in map {
892                    if !first {
893                        output.push(';');
894                    }
895                    output.push('\n');
896                    output.push_str(&indent_str);
897                    first = false;
898
899                    output.push_str(key);
900                    output.push_str(" = ");
901                    let val_str = to_string_format_impl(val, next_indent, true)?;
902                    output.push_str(&val_str);
903                }
904
905                if !map.is_empty() {
906                    output.push(';');
907                }
908                output.push('\n');
909                output.push_str(&" ".repeat(indent_level * INDENT_SIZE));
910                output.push('}');
911                Ok(output)
912            }
913        }
914    }
915}
916
917/// Deserializer implementation for Value
918impl<'de> Deserializer<'de> for Value {
919    type Error = Error;
920
921    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
922    where
923        V: Visitor<'de>,
924    {
925        match self {
926            Value::Bool(b) => visitor.visit_bool(b),
927            Value::Integer(i) => visitor.visit_i32(i),
928            Value::Integer64(i) => visitor.visit_i64(i),
929            Value::Float(f) => visitor.visit_f64(f),
930            Value::String(s) => visitor.visit_string(s),
931            Value::Array(arr) | Value::List(arr) => {
932                visitor.visit_seq(SeqDeserializer::new(arr.into_iter()))
933            }
934            Value::Group(map) => visitor.visit_map(MapDeserializer::new(map.into_iter())),
935        }
936    }
937
938    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
939    where
940        V: Visitor<'de>,
941    {
942        visitor.visit_some(self)
943    }
944
945    serde::forward_to_deserialize_any! {
946        bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string
947        bytes byte_buf unit unit_struct newtype_struct seq tuple
948        tuple_struct map struct enum identifier ignored_any
949    }
950}
951
952struct SeqDeserializer {
953    iter: std::vec::IntoIter<Value>,
954}
955
956impl SeqDeserializer {
957    fn new(iter: std::vec::IntoIter<Value>) -> Self {
958        SeqDeserializer { iter }
959    }
960}
961
962impl<'de> SeqAccess<'de> for SeqDeserializer {
963    type Error = Error;
964
965    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
966    where
967        T: de::DeserializeSeed<'de>,
968    {
969        match self.iter.next() {
970            Some(value) => seed.deserialize(value).map(Some),
971            None => Ok(None),
972        }
973    }
974}
975
976struct MapDeserializer {
977    iter: indexmap::map::IntoIter<String, Value>,
978    value: Option<Value>,
979}
980
981impl MapDeserializer {
982    fn new(iter: indexmap::map::IntoIter<String, Value>) -> Self {
983        MapDeserializer { iter, value: None }
984    }
985}
986
987impl<'de> MapAccess<'de> for MapDeserializer {
988    type Error = Error;
989
990    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
991    where
992        K: de::DeserializeSeed<'de>,
993    {
994        match self.iter.next() {
995            Some((key, value)) => {
996                self.value = Some(value);
997                seed.deserialize(Value::String(key)).map(Some)
998            }
999            None => Ok(None),
1000        }
1001    }
1002
1003    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
1004    where
1005        V: de::DeserializeSeed<'de>,
1006    {
1007        match self.value.take() {
1008            Some(value) => seed.deserialize(value),
1009            None => Err(Error::Message("value is missing".to_string())),
1010        }
1011    }
1012}
1013
1014/// A libconfig document that tracks top-level formatting.
1015///
1016/// `Config` wraps a `Value` and remembers whether the outer group uses
1017/// implicit format (no braces) or explicit format (`{...}`).
1018///
1019/// Create an empty config with [`Config::new`], parse from a string with
1020/// [`Config::from_str`], or wrap an existing `Value` with `Config::from(value)`.
1021///
1022/// `Config` derefs to `Value`, so all `Value` methods (indexing, lookup,
1023/// set, remove) work directly on a `Config`.
1024///
1025/// # Examples
1026///
1027/// ```
1028/// use libconfig::{Config, Value};
1029///
1030/// let mut config = Config::new();
1031/// config.set("name", Value::String("test".into()));
1032/// config.set("version", Value::Integer(42));
1033///
1034/// assert_eq!(config["name"], "test");
1035/// assert_eq!(config["version"], 42);
1036///
1037/// let output = config.to_string().unwrap();
1038/// assert_eq!(output, "name = \"test\";\nversion = 42;");
1039/// ```
1040#[derive(Debug, Clone, PartialEq)]
1041pub struct Config {
1042    /// The root value of the configuration
1043    pub value: Value,
1044    /// Whether the outer group has explicit braces
1045    pub explicit_braces: bool,
1046}
1047
1048impl Config {
1049    /// Create a new empty Config with implicit outer group format.
1050    pub fn new() -> Self {
1051        Config {
1052            value: Value::Group(Map::new()),
1053            explicit_braces: false,
1054        }
1055    }
1056
1057    /// Parse a libconfig string into a `Config`, automatically detecting
1058    /// whether the input uses an implicit group (no outer braces) or
1059    /// explicit group (`{...}`).
1060    ///
1061    /// # Examples
1062    ///
1063    /// ```
1064    /// use libconfig::Config;
1065    ///
1066    /// // Implicit group (no braces)
1067    /// let config = Config::from_str("a = 1; b = 2;").unwrap();
1068    /// assert!(!config.explicit_braces);
1069    /// assert_eq!(config["a"], 1);
1070    ///
1071    /// // Explicit group (with braces)
1072    /// let config = Config::from_str("{ a = 1; b = 2; }").unwrap();
1073    /// assert!(config.explicit_braces);
1074    /// assert_eq!(config["a"], 1);
1075    /// ```
1076    pub fn from_str(s: &str) -> Result<Config> {
1077        let trimmed = s.trim_start();
1078        let explicit_braces = trimmed.starts_with('{');
1079        let value: Value = crate::from_str(s)?;
1080        Ok(Config {
1081            value,
1082            explicit_braces,
1083        })
1084    }
1085
1086    /// Read and parse a libconfig file into a `Config`, automatically
1087    /// detecting whether the input uses an implicit or explicit group.
1088    ///
1089    /// # Examples
1090    ///
1091    /// ```no_run
1092    /// use libconfig::Config;
1093    ///
1094    /// let config = Config::from_file("settings.cfg").unwrap();
1095    /// println!("{}", config["name"]);
1096    /// ```
1097    pub fn from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Config> {
1098        let contents = std::fs::read_to_string(path)
1099            .map_err(|e| Error::Message(format!("failed to read file: {}", e)))?;
1100        Config::from_str(&contents)
1101    }
1102
1103    /// Serialize this config to a libconfig string, respecting
1104    /// the `explicit_braces` setting.
1105    pub fn to_string(&self) -> Result<String> {
1106        to_string_format_impl(&self.value, 0, self.explicit_braces)
1107    }
1108}
1109
1110impl Default for Config {
1111    fn default() -> Self {
1112        Config::new()
1113    }
1114}
1115
1116impl From<Value> for Config {
1117    fn from(value: Value) -> Self {
1118        Config {
1119            value,
1120            explicit_braces: false,
1121        }
1122    }
1123}
1124
1125impl std::ops::Deref for Config {
1126    type Target = Value;
1127
1128    fn deref(&self) -> &Value {
1129        &self.value
1130    }
1131}
1132
1133impl std::ops::DerefMut for Config {
1134    fn deref_mut(&mut self) -> &mut Value {
1135        &mut self.value
1136    }
1137}
1138
1139impl fmt::Display for Config {
1140    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1141        match self.to_string() {
1142            Ok(s) => write!(f, "{}", s),
1143            Err(e) => write!(f, "<error: {}>", e),
1144        }
1145    }
1146}
1147
1148impl Serialize for Config {
1149    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
1150    where
1151        S: Serializer,
1152    {
1153        self.value.serialize(serializer)
1154    }
1155}
1156
1157#[cfg(test)]
1158mod tests {
1159    use super::*;
1160    use crate::from_str;
1161
1162    #[test]
1163    fn test_value_types() {
1164        let v = Value::Bool(true);
1165        assert!(v.is_bool());
1166        assert_eq!(v.as_bool(), Some(true));
1167
1168        let v = Value::Integer(42);
1169        assert!(v.is_i32());
1170        assert_eq!(v.as_i32(), Some(42));
1171
1172        let v = Value::Float(3.14);
1173        assert!(v.is_float());
1174        assert_eq!(v.as_f64(), Some(3.14));
1175
1176        let v = Value::String("hello".to_string());
1177        assert!(v.is_string());
1178        assert_eq!(v.as_str(), Some("hello"));
1179    }
1180
1181    #[test]
1182    fn test_value_indexing() {
1183        let config = r#"
1184            {
1185                name = "Test";
1186                count = 42;
1187                items = [1, 2, 3];
1188            }
1189        "#;
1190
1191        let v: Value = from_str(config).unwrap();
1192        assert_eq!(v["name"], "Test");
1193        assert_eq!(v["count"], 42);
1194        assert_eq!(v["items"][0], 1);
1195        assert_eq!(v["items"][1], 2);
1196    }
1197
1198    #[test]
1199    fn test_value_lookup() {
1200        let config = r#"
1201            {
1202                application = {
1203                    window = {
1204                        title = "My App";
1205                        size = { w = 640; h = 480; };
1206                    };
1207                };
1208            }
1209        "#;
1210
1211        let v: Value = from_str(config).unwrap();
1212        assert_eq!(
1213            v.lookup("application.window.title")
1214                .and_then(|v| v.as_str()),
1215            Some("My App")
1216        );
1217        assert_eq!(
1218            v.lookup("application.window.size")
1219                .and_then(|v| v.get("w"))
1220                .and_then(|v| v.as_i32()),
1221            Some(640)
1222        );
1223    }
1224
1225    #[test]
1226    fn test_value_lookup_with_array_index() {
1227        let config = r#"
1228            {
1229                name = "Test";
1230                items = [10, 20, 30];
1231                nested = {
1232                    ports = [80, 443];
1233                };
1234            }
1235        "#;
1236
1237        let v: Value = from_str(config).unwrap();
1238
1239        // Direct array index
1240        assert_eq!(v.lookup("items.0").and_then(|v| v.as_i32()), Some(10));
1241        assert_eq!(v.lookup("items.1").and_then(|v| v.as_i32()), Some(20));
1242        assert_eq!(v.lookup("items.2").and_then(|v| v.as_i32()), Some(30));
1243
1244        // Nested group then array index
1245        assert_eq!(
1246            v.lookup("nested.ports.0").and_then(|v| v.as_i32()),
1247            Some(80)
1248        );
1249        assert_eq!(
1250            v.lookup("nested.ports.1").and_then(|v| v.as_i32()),
1251            Some(443)
1252        );
1253
1254        // Out of bounds returns None
1255        assert!(v.lookup("items.5").is_none());
1256
1257        // Index on non-array returns None
1258        assert!(v.lookup("name.0").is_none());
1259
1260        // Index via [] operator
1261        assert_eq!(v["items.0"], 10);
1262        assert_eq!(v["nested.ports.1"], 443);
1263    }
1264
1265    #[test]
1266    fn test_value_comparison() {
1267        let v = Value::Bool(true);
1268        assert!(v == true);
1269
1270        let v = Value::Integer(42);
1271        assert!(v == 42);
1272
1273        let v = Value::String("hello".to_string());
1274        assert!(v == "hello");
1275    }
1276
1277    #[test]
1278    fn test_value_round_trip() {
1279        let config = r#"
1280            {
1281                name = "Test";
1282                version = 1;
1283                enabled = true;
1284                pi = 3.14;
1285                items = [1, 2, 3];
1286            }
1287        "#;
1288
1289        let v: Value = from_str(config).unwrap();
1290        let serialized = crate::to_string(&v).unwrap();
1291        let v2: Value = from_str(&serialized).unwrap();
1292
1293        assert_eq!(v["name"], v2["name"]);
1294        assert_eq!(v["version"], v2["version"]);
1295        assert_eq!(v["enabled"], v2["enabled"]);
1296    }
1297
1298    // === Path parsing tests ===
1299
1300    #[test]
1301    fn test_parse_path_dotted_keys() {
1302        let segs = parse_path("a.b.c").unwrap();
1303        assert_eq!(
1304            segs,
1305            vec![
1306                PathSegment::Key("a"),
1307                PathSegment::Key("b"),
1308                PathSegment::Key("c"),
1309            ]
1310        );
1311    }
1312
1313    #[test]
1314    fn test_parse_path_bracket_index() {
1315        let segs = parse_path("items.[0].title").unwrap();
1316        assert_eq!(
1317            segs,
1318            vec![
1319                PathSegment::Key("items"),
1320                PathSegment::Index(0),
1321                PathSegment::Key("title"),
1322            ]
1323        );
1324    }
1325
1326    #[test]
1327    fn test_parse_path_bare_numeric() {
1328        let segs = parse_path("items.0").unwrap();
1329        assert_eq!(segs, vec![PathSegment::Key("items"), PathSegment::Index(0)]);
1330    }
1331
1332    #[test]
1333    fn test_parse_path_single_segment() {
1334        assert_eq!(
1335            parse_path("version").unwrap(),
1336            vec![PathSegment::Key("version")]
1337        );
1338    }
1339
1340    #[test]
1341    fn test_parse_path_invalid() {
1342        assert!(parse_path("").is_none());
1343        assert!(parse_path("a..b").is_none());
1344        assert!(parse_path(".a").is_none());
1345        assert!(parse_path("a.").is_none());
1346        assert!(parse_path("items.[abc]").is_none());
1347        assert!(parse_path("items.[-1]").is_none());
1348        assert!(parse_path("items.[]").is_none());
1349    }
1350
1351    // === Bracket notation lookup tests ===
1352
1353    #[test]
1354    fn test_lookup_bracket_notation() {
1355        let config = r#"
1356            {
1357                books = (
1358                    { title = "Treasure Island"; price = 29; },
1359                    { title = "Snow Crash"; price = 9; }
1360                );
1361            }
1362        "#;
1363        let v: Value = from_str(config).unwrap();
1364
1365        // Bracket notation
1366        assert_eq!(
1367            v.lookup("books.[0].title").and_then(|v| v.as_str()),
1368            Some("Treasure Island")
1369        );
1370        assert_eq!(
1371            v.lookup("books.[1].price").and_then(|v| v.as_i32()),
1372            Some(9)
1373        );
1374
1375        // Bare numeric still works
1376        assert_eq!(
1377            v.lookup("books.0.title").and_then(|v| v.as_str()),
1378            Some("Treasure Island")
1379        );
1380    }
1381
1382    #[test]
1383    fn test_lookup_mut_bracket_notation() {
1384        let config = r#"{ items = [10, 20, 30]; }"#;
1385        let mut v: Value = from_str(config).unwrap();
1386
1387        *v.lookup_mut("items.[1]").unwrap() = Value::Integer(99);
1388        assert_eq!(v.lookup("items.[1]").unwrap().as_i32(), Some(99));
1389        assert_eq!(v.lookup("items.1").unwrap().as_i32(), Some(99));
1390    }
1391
1392    // === Set tests ===
1393
1394    #[test]
1395    fn test_set_existing_key() {
1396        let mut v: Value = from_str(r#"{ name = "old"; }"#).unwrap();
1397        assert_eq!(v.set("name", Value::String("new".to_string())), Some(()));
1398        assert_eq!(v.lookup("name").unwrap().as_str(), Some("new"));
1399    }
1400
1401    #[test]
1402    fn test_set_new_key() {
1403        let mut v: Value = from_str(r#"{ a = 1; }"#).unwrap();
1404        assert_eq!(v.set("b", Value::Integer(2)), Some(()));
1405        assert_eq!(v.lookup("b").unwrap().as_i32(), Some(2));
1406    }
1407
1408    #[test]
1409    fn test_set_creates_intermediate_groups() {
1410        let mut v = Value::Group(IndexMap::new());
1411        assert_eq!(v.set("a.b.c", Value::Integer(42)), Some(()));
1412        assert_eq!(v.lookup("a.b.c").unwrap().as_i32(), Some(42));
1413        assert!(v.lookup("a").unwrap().is_group());
1414        assert!(v.lookup("a.b").unwrap().is_group());
1415    }
1416
1417    #[test]
1418    fn test_set_array_element() {
1419        let mut v: Value = from_str(r#"{ items = [1, 2, 3]; }"#).unwrap();
1420        assert_eq!(v.set("items.[0]", Value::Integer(99)), Some(()));
1421        assert_eq!(v.lookup("items.[0]").unwrap().as_i32(), Some(99));
1422    }
1423
1424    #[test]
1425    fn test_set_array_out_of_bounds() {
1426        let mut v: Value = from_str(r#"{ items = [1, 2]; }"#).unwrap();
1427        assert_eq!(v.set("items.[5]", Value::Integer(99)), None);
1428    }
1429
1430    #[test]
1431    fn test_set_on_scalar_fails() {
1432        let mut v: Value = from_str(r#"{ name = "hello"; }"#).unwrap();
1433        assert_eq!(v.set("name.child", Value::Integer(1)), None);
1434    }
1435
1436    #[test]
1437    fn test_set_deeply_nested() {
1438        let mut v = Value::Group(IndexMap::new());
1439        assert_eq!(
1440            v.set("level1.level2.level3.level4", Value::Bool(true)),
1441            Some(())
1442        );
1443        assert_eq!(
1444            v.lookup("level1.level2.level3.level4").unwrap().as_bool(),
1445            Some(true)
1446        );
1447    }
1448
1449    #[test]
1450    fn test_set_into_list_element_group() {
1451        let config = r#"
1452            {
1453                books = (
1454                    { title = "Old Title"; }
1455                );
1456            }
1457        "#;
1458        let mut v: Value = from_str(config).unwrap();
1459        assert_eq!(
1460            v.set("books.[0].title", Value::String("New Title".to_string())),
1461            Some(())
1462        );
1463        assert_eq!(
1464            v.lookup("books.[0].title").unwrap().as_str(),
1465            Some("New Title")
1466        );
1467    }
1468
1469    // === Remove tests ===
1470
1471    #[test]
1472    fn test_remove_group_key() {
1473        let mut v: Value = from_str(r#"{ a = 1; b = 2; c = 3; }"#).unwrap();
1474        let removed = v.remove("b");
1475        assert_eq!(removed, Some(Value::Integer(2)));
1476        assert!(v.lookup("b").is_none());
1477        assert_eq!(v.lookup("a").unwrap().as_i32(), Some(1));
1478        assert_eq!(v.lookup("c").unwrap().as_i32(), Some(3));
1479    }
1480
1481    #[test]
1482    fn test_remove_array_element() {
1483        let mut v: Value = from_str(r#"{ items = [10, 20, 30]; }"#).unwrap();
1484        let removed = v.remove("items.[1]");
1485        assert_eq!(removed, Some(Value::Integer(20)));
1486        // Elements shift: [10, 30]
1487        assert_eq!(v.lookup("items.[0]").unwrap().as_i32(), Some(10));
1488        assert_eq!(v.lookup("items.[1]").unwrap().as_i32(), Some(30));
1489        assert!(v.lookup("items.[2]").is_none());
1490    }
1491
1492    #[test]
1493    fn test_remove_nested() {
1494        let config = r#"
1495            {
1496                database = {
1497                    host = "localhost";
1498                    port = 5432;
1499                };
1500            }
1501        "#;
1502        let mut v: Value = from_str(config).unwrap();
1503        let removed = v.remove("database.host");
1504        assert_eq!(removed, Some(Value::String("localhost".to_string())));
1505        assert!(v.lookup("database.host").is_none());
1506        assert_eq!(v.lookup("database.port").unwrap().as_i32(), Some(5432));
1507    }
1508
1509    #[test]
1510    fn test_remove_nonexistent() {
1511        let mut v: Value = from_str(r#"{ a = 1; }"#).unwrap();
1512        assert_eq!(v.remove("z"), None);
1513        assert_eq!(v.remove("a.b"), None);
1514    }
1515
1516    #[test]
1517    fn test_remove_index_out_of_bounds() {
1518        let mut v: Value = from_str(r#"{ items = [1, 2]; }"#).unwrap();
1519        assert_eq!(v.remove("items.[5]"), None);
1520    }
1521
1522    #[test]
1523    fn test_remove_entire_subtree() {
1524        let config = r#"
1525            {
1526                app = {
1527                    window = { title = "hi"; };
1528                    debug = false;
1529                };
1530            }
1531        "#;
1532        let mut v: Value = from_str(config).unwrap();
1533        let removed = v.remove("app.window");
1534        assert!(removed.unwrap().is_group());
1535        assert!(v.lookup("app.window").is_none());
1536        assert_eq!(v.lookup("app.debug").unwrap().as_bool(), Some(false));
1537    }
1538
1539    #[test]
1540    fn test_remove_bare_numeric_index() {
1541        let mut v: Value = from_str(r#"{ items = [10, 20, 30]; }"#).unwrap();
1542        let removed = v.remove("items.0");
1543        assert_eq!(removed, Some(Value::Integer(10)));
1544        assert_eq!(v.lookup("items.0").unwrap().as_i32(), Some(20));
1545    }
1546
1547    // === Ordering and format preservation tests ===
1548
1549    #[test]
1550    fn test_ordering_preserved_in_round_trip() {
1551        let input = r#"{
1552  first = 1;
1553  second = 2;
1554  third = 3;
1555  fourth = 4;
1556}"#;
1557        let v: Value = from_str(input).unwrap();
1558        let output = Config::from(v.clone()).to_string().unwrap();
1559
1560        // Parse both and verify key order
1561        let v_output: Value = from_str(&output).unwrap();
1562        if let Value::Group(map) = v {
1563            if let Value::Group(map_output) = v_output {
1564                let keys1: Vec<&String> = map.keys().collect();
1565                let keys2: Vec<&String> = map_output.keys().collect();
1566                assert_eq!(keys1, keys2);
1567                assert_eq!(keys1, vec!["first", "second", "third", "fourth"]);
1568            }
1569        }
1570    }
1571
1572    #[test]
1573    fn test_config_implicit_no_outer_braces() {
1574        let input = "a = 1;\nb = 2;\nc = 3;";
1575        let v: Value = from_str(input).unwrap();
1576
1577        let output = Config::from(v).to_string().unwrap();
1578
1579        // Implicit config omits outer braces
1580        assert!(!output.trim_start().starts_with('{'));
1581        assert!(!output.trim_end().ends_with('}'));
1582
1583        // Should contain the keys
1584        assert!(output.contains("a = 1"));
1585        assert!(output.contains("b = 2"));
1586        assert!(output.contains("c = 3"));
1587    }
1588
1589    #[test]
1590    fn test_config_explicit_outer_braces() {
1591        let input = "a = 1;\nb = 2;\nc = 3;";
1592        let v: Value = from_str(input).unwrap();
1593
1594        let mut config = Config::from(v);
1595        config.explicit_braces = true;
1596        let output = config.to_string().unwrap();
1597
1598        // Explicit config adds outer braces
1599        assert!(output.trim_start().starts_with('{'));
1600        assert!(output.trim_end().ends_with('}'));
1601
1602        // Should contain the keys
1603        assert!(output.contains("a = 1"));
1604        assert!(output.contains("b = 2"));
1605        assert!(output.contains("c = 3"));
1606    }
1607
1608    #[test]
1609    fn test_config_implicit_vs_explicit() {
1610        let input = "{\n  a = 1;\n  b = 2;\n  c = 3;\n}";
1611        let v: Value = from_str(input).unwrap();
1612
1613        // Config::from produces implicit format
1614        let output = Config::from(v.clone()).to_string().unwrap();
1615        assert!(!output.trim_start().starts_with('{'));
1616        assert!(!output.trim_end().ends_with('}'));
1617
1618        // Setting explicit_braces produces explicit format
1619        let mut config = Config::from(v);
1620        config.explicit_braces = true;
1621        let output_braces = config.to_string().unwrap();
1622        assert!(output_braces.trim_start().starts_with('{'));
1623        assert!(output_braces.trim_end().ends_with('}'));
1624    }
1625
1626    #[test]
1627    fn test_nested_groups_have_braces() {
1628        let input = r#"{
1629  outer = 1;
1630  nested = {
1631    inner = 2;
1632  };
1633}"#;
1634        let v: Value = from_str(input).unwrap();
1635        let output = Config::from(v).to_string().unwrap();
1636
1637        // Outer group should not have braces (implicit format)
1638        assert!(!output.trim_start().starts_with('{'));
1639
1640        // Nested groups should still have braces
1641        assert!(output.contains("nested = {"));
1642
1643        // Parse and verify structure
1644        let v2: Value = from_str(&output).unwrap();
1645        assert_eq!(v2["outer"], 1);
1646        assert_eq!(v2["nested.inner"], 2);
1647    }
1648
1649    #[test]
1650    fn test_ordering_with_mixed_types() {
1651        let input = r#"{
1652  string_first = "hello";
1653  int_second = 42;
1654  bool_third = true;
1655  float_fourth = 3.14;
1656  array_fifth = [1, 2, 3];
1657}"#;
1658        let v: Value = from_str(input).unwrap();
1659
1660        if let Value::Group(map) = &v {
1661            let keys: Vec<&String> = map.keys().collect();
1662            assert_eq!(
1663                keys,
1664                vec![
1665                    "string_first",
1666                    "int_second",
1667                    "bool_third",
1668                    "float_fourth",
1669                    "array_fifth"
1670                ]
1671            );
1672        }
1673
1674        let output = Config::from(v).to_string().unwrap();
1675        let v2: Value = from_str(&output).unwrap();
1676
1677        // Verify order is preserved after round-trip
1678        if let Value::Group(map) = &v2 {
1679            let keys: Vec<&String> = map.keys().collect();
1680            assert_eq!(
1681                keys,
1682                vec![
1683                    "string_first",
1684                    "int_second",
1685                    "bool_third",
1686                    "float_fourth",
1687                    "array_fifth"
1688                ]
1689            );
1690        }
1691    }
1692
1693    #[test]
1694    fn test_adding_new_keys_appends_to_end() {
1695        let input = "a = 1;\nb = 2;";
1696        let mut v: Value = from_str(input).unwrap();
1697
1698        // Add a new key
1699        v.set("c", Value::Integer(3)).unwrap();
1700
1701        if let Value::Group(map) = &v {
1702            let keys: Vec<&String> = map.keys().collect();
1703            assert_eq!(keys, vec!["a", "b", "c"]);
1704        }
1705
1706        let output = Config::from(v).to_string().unwrap();
1707
1708        // Verify new key appears at the end
1709        let a_pos = output.find("a = 1").unwrap();
1710        let b_pos = output.find("b = 2").unwrap();
1711        let c_pos = output.find("c = 3").unwrap();
1712
1713        assert!(a_pos < b_pos);
1714        assert!(b_pos < c_pos);
1715    }
1716
1717    #[test]
1718    fn test_implicit_group_round_trip_exact() {
1719        let input = "name = \"test\";\nversion = 42;";
1720        let v: Value = from_str(input).unwrap();
1721        let output = Config::from(v).to_string().unwrap();
1722
1723        // Output should match input exactly
1724        assert_eq!(output, input);
1725
1726        // Round-trip should be stable
1727        let v2: Value = from_str(&output).unwrap();
1728        let output2 = Config::from(v2).to_string().unwrap();
1729        assert_eq!(output, output2);
1730    }
1731
1732    #[test]
1733    fn test_nested_indentation() {
1734        let input = r#"{
1735  outer = 1;
1736  nested = {
1737    inner = 2;
1738    deep = {
1739      value = 3;
1740    };
1741  };
1742  another = 4;
1743}"#;
1744        let v: Value = from_str(input).unwrap();
1745        let output = Config::from(v).to_string().unwrap();
1746
1747        // Top-level keys have no indentation (implicit outer group)
1748        assert!(output.contains("outer = 1"));
1749        assert!(output.contains("nested = {"));
1750        // Nested keys get 2-space indentation
1751        assert!(output.contains("  inner = 2"));
1752        assert!(output.contains("  deep = {"));
1753        // Deeply nested keys get 4-space indentation
1754        assert!(output.contains("    value = 3"));
1755
1756        // Verify it can be parsed back
1757        let v2: Value = from_str(&output).unwrap();
1758        assert_eq!(v2["outer"], 1);
1759        assert_eq!(v2["nested.inner"], 2);
1760        assert_eq!(v2["nested.deep.value"], 3);
1761        assert_eq!(v2["another"], 4);
1762    }
1763
1764    #[test]
1765    fn test_implicit_group_with_nested_explicit_groups() {
1766        let input = r#"top_level = 1;
1767nested = {
1768  inner = 2;
1769};
1770also_top = 3;"#;
1771        let v: Value = from_str(input).unwrap();
1772        let output = Config::from(v).to_string().unwrap();
1773
1774        // Top level should not have braces (implicit format)
1775        assert!(!output.trim().starts_with('{'));
1776
1777        // Nested group should have braces
1778        assert!(output.contains("nested = {"));
1779        assert!(output.contains("  inner = 2"));
1780
1781        // Parse and verify
1782        let v2: Value = from_str(&output).unwrap();
1783        assert_eq!(v2["top_level"], 1);
1784        assert_eq!(v2["nested.inner"], 2);
1785        assert_eq!(v2["also_top"], 3);
1786    }
1787
1788    #[test]
1789    fn test_deeply_nested_groups() {
1790        let input = r#"{
1791  level1 = {
1792    level2 = {
1793      level3 = {
1794        value = 42;
1795      };
1796    };
1797  };
1798}"#;
1799        let v: Value = from_str(input).unwrap();
1800        let output = Config::from(v).to_string().unwrap();
1801
1802        // Top-level is implicit (no braces, no indent)
1803        // Each nested level adds 2-space indentation
1804        assert!(output.contains("level1 = {"));
1805        assert!(output.contains("  level2 = {"));
1806        assert!(output.contains("    level3 = {"));
1807        assert!(output.contains("      value = 42"));
1808    }
1809
1810    // === Config wrapper tests ===
1811
1812    #[test]
1813    fn test_config_implicit_round_trip() {
1814        let input = "name = \"test\";\nversion = 42;";
1815        let config = Config::from_str(input).unwrap();
1816
1817        assert!(!config.explicit_braces);
1818        assert_eq!(config["name"], "test");
1819        assert_eq!(config["version"], 42);
1820
1821        let output = config.to_string().unwrap();
1822        assert_eq!(output, input);
1823    }
1824
1825    #[test]
1826    fn test_config_explicit_round_trip() {
1827        let input = "{\n  name = \"test\";\n  version = 42;\n}";
1828        let config = Config::from_str(input).unwrap();
1829
1830        assert!(config.explicit_braces);
1831        assert_eq!(config["name"], "test");
1832
1833        let output = config.to_string().unwrap();
1834        assert!(output.starts_with('{'));
1835        assert!(output.ends_with('}'));
1836    }
1837
1838    #[test]
1839    fn test_config_deref_lookup() {
1840        let config = Config::from_str("a = 1; b = { c = 2; };").unwrap();
1841
1842        // Deref allows Value methods directly
1843        assert_eq!(config.lookup("b.c").unwrap().as_i32(), Some(2));
1844        assert!(config.is_group());
1845    }
1846
1847    #[test]
1848    fn test_config_deref_mut() {
1849        let mut config = Config::from_str("a = 1; b = 2;").unwrap();
1850
1851        config.set("c", Value::Integer(3)).unwrap();
1852        assert_eq!(config["c"], 3);
1853
1854        let output = config.to_string().unwrap();
1855        assert!(output.contains("c = 3"));
1856    }
1857
1858    #[test]
1859    fn test_config_display() {
1860        let config = Config::from_str("x = 10; y = 20;").unwrap();
1861        let displayed = format!("{}", config);
1862        assert!(displayed.contains("x = 10"));
1863        assert!(displayed.contains("y = 20"));
1864        assert!(!displayed.starts_with('{'));
1865    }
1866
1867    #[test]
1868    fn test_config_new_empty() {
1869        let mut config = Config::new();
1870        assert!(!config.explicit_braces);
1871        assert!(config.is_group());
1872
1873        config.set("key", Value::String("val".to_string())).unwrap();
1874        let output = config.to_string().unwrap();
1875        assert_eq!(output, "key = \"val\";");
1876    }
1877
1878    #[test]
1879    fn test_config_from_value() {
1880        let mut map = Map::new();
1881        map.insert("key".to_string(), Value::String("val".to_string()));
1882        let config = Config::from(Value::Group(map));
1883
1884        assert!(!config.explicit_braces);
1885        let output = config.to_string().unwrap();
1886        assert_eq!(output, "key = \"val\";");
1887    }
1888
1889    #[test]
1890    fn test_config_from_value_explicit() {
1891        let mut map = Map::new();
1892        map.insert("key".to_string(), Value::String("val".to_string()));
1893        let mut config = Config::from(Value::Group(map));
1894        config.explicit_braces = true;
1895
1896        assert!(config.explicit_braces);
1897        let output = config.to_string().unwrap();
1898        assert!(output.starts_with('{'));
1899        assert!(output.contains("key = \"val\""));
1900    }
1901
1902    #[test]
1903    fn test_config_default() {
1904        let config = Config::default();
1905        assert!(!config.explicit_braces);
1906        assert!(config.is_group());
1907        assert_eq!(config.as_group().unwrap().len(), 0);
1908    }
1909
1910    #[test]
1911    fn test_config_serialize() {
1912        let config = Config::from_str("a = 1; b = 2;").unwrap();
1913        // Serialize through serde (always produces braces)
1914        let serde_output = crate::to_string(&config).unwrap();
1915        assert!(serde_output.starts_with('{'));
1916
1917        // Config::to_string preserves format
1918        let format_output = config.to_string().unwrap();
1919        assert!(!format_output.starts_with('{'));
1920    }
1921}