hocon_rs/raw/
raw_object.rs

1use crate::join;
2use crate::raw::field::ObjectField;
3use crate::raw::raw_string::RawString;
4use crate::raw::raw_value::RawValue;
5use crate::{path::Path, value::Value};
6use derive_more::{Constructor, Deref, DerefMut};
7use std::fmt::{Display, Formatter};
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Deref, DerefMut, Constructor)]
10pub struct RawObject(pub Vec<ObjectField>);
11
12impl RawObject {
13    pub fn from_entries<I>(entries: Vec<(RawString, RawValue)>) -> Self
14    where
15        I: IntoIterator<Item = (RawString, RawValue)>,
16    {
17        let fields = entries
18            .into_iter()
19            .map(|(k, v)| ObjectField::key_value(k, v))
20            .collect();
21        Self::new(fields)
22    }
23
24    pub fn remove_by_path(&mut self, path: &Path) -> Option<ObjectField> {
25        let mut remove_index = None;
26        for (index, field) in self.iter_mut().enumerate().rev() {
27            match field {
28                ObjectField::Inclusion { inclusion, .. } => {
29                    if let Some(obj) = &mut inclusion.val {
30                        return obj.remove_by_path(path);
31                    }
32                }
33                ObjectField::KeyValue { key, value, .. } => {
34                    let k = &key.as_path();
35                    if path.starts_with1(k) {
36                        match path.sub_path(k.len()) {
37                            None => {
38                                remove_index = Some(index);
39                                break;
40                            }
41                            Some(sub_path) => {
42                                if let RawValue::Object(obj) = value {
43                                    return obj.remove_by_path(sub_path);
44                                }
45                            }
46                        }
47                    }
48                }
49                ObjectField::NewlineComment(_) => {}
50            }
51        }
52        remove_index.map(|index| self.remove(index))
53    }
54
55    /// Removes all object fields from the given path, preserving their original
56    /// order but reversed relative to the file.
57    pub fn remove_all_by_path(&mut self, path: &Path) -> Vec<ObjectField> {
58        let mut results = vec![];
59        let mut remove_indices = vec![]; // These indices are stored in reverse order
60        for (index, field) in self.iter_mut().enumerate().rev() {
61            match field {
62                ObjectField::Inclusion { inclusion, .. } => {
63                    if let Some(obj) = &mut inclusion.val {
64                        results.extend(obj.remove_all_by_path(path));
65                    }
66                }
67                ObjectField::KeyValue { key, value, .. } => {
68                    let k = &key.as_path();
69                    if path.starts_with1(k) {
70                        match path.sub_path(k.len()) {
71                            None => {
72                                remove_indices.push(index);
73                            }
74                            Some(sub_path) => {
75                                if let RawValue::Object(obj) = value {
76                                    results.extend(obj.remove_all_by_path(sub_path));
77                                }
78                            }
79                        }
80                    }
81                }
82                ObjectField::NewlineComment(_) => {}
83            }
84        }
85        for idx in remove_indices {
86            results.push(self.remove(idx));
87        }
88        results
89    }
90
91    pub fn get_by_path(&self, path: &Path) -> Option<&RawValue> {
92        for field in self.iter().rev() {
93            match field {
94                ObjectField::Inclusion { inclusion, .. } => {
95                    if let Some(obj) = &inclusion.val {
96                        return obj.get_by_path(path);
97                    }
98                }
99                ObjectField::KeyValue { key, value, .. } => {
100                    let k = &key.as_path();
101                    if path.starts_with1(k) {
102                        match path.sub_path(k.len()) {
103                            None => return Some(value),
104                            Some(sub_path) => {
105                                if let RawValue::Object(obj) = value {
106                                    return obj.get_by_path(sub_path);
107                                }
108                            }
109                        }
110                    }
111                }
112                ObjectField::NewlineComment(_) => {}
113            }
114        }
115        None
116    }
117
118    pub fn get_by_path_mut(&mut self, path: &Path) -> Option<&mut RawValue> {
119        for field in self.iter_mut().rev() {
120            match field {
121                ObjectField::Inclusion { inclusion, .. } => {
122                    if let Some(obj) = &mut inclusion.val {
123                        return obj.get_by_path_mut(path);
124                    }
125                }
126                ObjectField::KeyValue { key, value, .. } => {
127                    let k = &key.as_path();
128                    if path.starts_with1(k) {
129                        match path.sub_path(k.len()) {
130                            None => return Some(value),
131                            Some(sub_path) => {
132                                if let RawValue::Object(obj) = value {
133                                    return obj.get_by_path_mut(sub_path);
134                                }
135                            }
136                        }
137                    }
138                }
139                ObjectField::NewlineComment(_) => {}
140            }
141        }
142        None
143    }
144
145    /// Merges two `RawObject`s into one.
146    ///
147    /// - If both objects contain the same key, the field from `right` takes precedence
148    ///   and overwrites the one from `left`.
149    /// - Fields that only exist in `left` are preserved.
150    /// - This follows HOCON’s rule that later definitions of the same key override
151    ///   earlier ones.
152    pub(crate) fn merge(mut left: Self, right: Self) -> Self {
153        left.0.extend(right.0);
154        left
155    }
156}
157
158impl Display for RawObject {
159    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
160        write!(f, "{{")?;
161        join(self.iter(), ", ", f)?;
162        write!(f, "}}")?;
163        Ok(())
164    }
165}
166
167impl From<Value> for RawValue {
168    fn from(val: Value) -> Self {
169        match val {
170            Value::Object(object) => {
171                let len = object.len();
172                let fields =
173                    object
174                        .into_iter()
175                        .fold(Vec::with_capacity(len), |mut acc, (key, value)| {
176                            let field = ObjectField::key_value(key, value);
177                            acc.push(field);
178                            acc
179                        });
180                RawValue::Object(RawObject::new(fields))
181            }
182            Value::Array(array) => RawValue::array(array.into_iter().map(Into::into).collect()),
183            Value::Boolean(boolean) => RawValue::Boolean(boolean),
184            Value::Null => RawValue::Null,
185            Value::String(string) => RawValue::String(string.into()),
186            Value::Number(number) => RawValue::Number(number),
187        }
188    }
189}