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