hocon_rs/merge/
value.rs

1use tracing::trace;
2
3use crate::{
4    error::Error,
5    merge::{
6        add_assign::AddAssign, array::Array, concat::Concat, delay_replacement::DelayReplacement,
7        object::Object, path::RefPath, substitution::Substitution,
8    },
9};
10use std::fmt::Write;
11use std::{cell::RefCell, fmt::Display};
12
13#[macro_export(local_inner_macros)]
14macro_rules! expect_variant {
15    ($expr:expr, $variant:path, mut) => {{
16        match &mut *$expr {
17            $variant(var) => var,
18            other => std::panic!(
19                "expected variant `{}`, got `{}`",
20                std::stringify!($variant),
21                other.ty()
22            ),
23        }
24    }};
25    ($expr:expr, $variant:path) => {{
26        match &*$expr {
27            $variant(var) => var,
28            other => std::panic!(
29                "expected variant `{}`, got `{}`",
30                std::stringify!($variant),
31                other.ty()
32            ),
33        }
34    }};
35}
36
37#[derive(Debug, Clone, PartialEq, Default)]
38pub(crate) enum Value {
39    Object(Object),
40    Array(Array),
41    Boolean(bool),
42    Null,
43    #[default]
44    None,
45    String(String),
46    Number(serde_json::Number),
47    Substitution(Substitution),
48    Concat(Concat),
49    AddAssign(AddAssign),
50    DelayReplacement(DelayReplacement),
51}
52
53impl Value {
54    pub(crate) fn object(o: impl Into<Object>) -> Value {
55        Value::Object(o.into())
56    }
57
58    pub(crate) fn array(a: impl Into<Array>) -> Value {
59        Value::Array(a.into())
60    }
61
62    pub(crate) fn string(s: impl Into<String>) -> Value {
63        Value::String(s.into())
64    }
65
66    pub(crate) fn number(n: serde_json::Number) -> Value {
67        Value::Number(n)
68    }
69
70    pub(crate) fn substitution(s: impl Into<Substitution>) -> Value {
71        Value::Substitution(s.into())
72    }
73
74    pub(crate) fn concat(c: impl Into<Concat>) -> Value {
75        Value::Concat(c.into())
76    }
77
78    pub(crate) fn add_assign(a: impl Into<AddAssign>) -> Value {
79        Value::AddAssign(a.into())
80    }
81
82    pub(crate) fn delay_replacement<I>(value: I) -> Value
83    where
84        I: IntoIterator<Item = Value>,
85    {
86        let d = DelayReplacement::from_iter(value);
87        Value::DelayReplacement(d.flatten())
88    }
89
90    pub(crate) fn ty(&self) -> &'static str {
91        match self {
92            Value::Object(_) => "object",
93            Value::Array(_) => "array",
94            Value::Boolean(_) => "boolean",
95            Value::Null => "null",
96            Value::None => "none",
97            Value::String(_) => "string",
98            Value::Number(_) => "number",
99            Value::Substitution(_) => "substitution",
100            Value::Concat(_) => "concat",
101            Value::AddAssign(_) => "add_assign",
102            Value::DelayReplacement(_) => "delay_replacement",
103        }
104    }
105
106    pub(crate) fn try_become_merged(&mut self) -> bool {
107        match self {
108            Value::Object(object) => object.try_become_merged(),
109            Value::Array(array) => array.try_become_merged(),
110            Value::Boolean(_) | Value::Null | Value::None | Value::String(_) | Value::Number(_) => {
111                true
112            }
113            Value::Substitution(_)
114            | Value::Concat(_)
115            | Value::AddAssign(_)
116            | Value::DelayReplacement(_) => false,
117        }
118    }
119
120    /// Replaces left value to right value if they are simple values. If value contains substitution,
121    /// it's impossible to determine the replace behavior, for different type values, right value will override left
122    /// value, for add assing(+=), right value will add to the left value(array), for object vlaues, it will trigger
123    /// a object merge operation. If there's any substitution exists in the value, it's impossible for now to determine the
124    /// replace behavior, so we construct a new dely replacement value wraps them for future resolve.
125    pub(crate) fn replace(path: &RefPath, left: Value, right: Value) -> crate::Result<Value> {
126        trace!("replace: `{}`: `{}` <- `{}`", path, left, right);
127        let new_val = match left {
128            Value::Object(mut obj_left) => match right {
129                Value::Object(right) => {
130                    // Merge two objects
131                    obj_left.merge(right, Some(path))?;
132                    Value::object(obj_left)
133                }
134                Value::Array(_)
135                | Value::Boolean(_)
136                | Value::Null
137                | Value::None
138                | Value::String(_)
139                | Value::Number(_) => right,
140                Value::Substitution(_) => {
141                    let left = Value::object(obj_left);
142                    Value::delay_replacement([left, right])
143                }
144                Value::Concat(concat) => {
145                    let try_resolved = concat.try_resolve(path)?;
146                    match try_resolved {
147                        Value::Object(object) => {
148                            obj_left.merge(object, Some(path))?;
149                            Value::object(obj_left)
150                        }
151                        Value::Concat(mut concat) => {
152                            let left = Value::object(obj_left);
153                            concat.push_front(RefCell::new(left), None);
154                            Value::concat(concat)
155                        }
156                        // Concat result must not be Substitution DelayReplacement
157                        other => other,
158                    }
159                }
160                Value::AddAssign(_) => {
161                    return Err(Error::ConcatenateDifferentType {
162                        path: path.to_string(),
163                        left_type: "object",
164                        right_type: right.ty(),
165                    });
166                }
167                Value::DelayReplacement(mut delay_merge) => {
168                    let left = Value::object(obj_left);
169                    delay_merge.push_front(RefCell::new(left));
170                    Value::DelayReplacement(delay_merge)
171                }
172            },
173            Value::Array(mut array_left) => match right {
174                Value::Substitution(_) | Value::DelayReplacement(_) => {
175                    Value::delay_replacement([Value::array(array_left), right])
176                }
177                Value::Concat(concat) => {
178                    let right = concat.try_resolve(path)?;
179                    match right {
180                        Value::Array(array) => {
181                            let left = Value::Array(array_left);
182                            let right = Value::Array(array);
183                            Self::concatenate(path, left, None, right)?
184                        }
185                        Value::Concat(concat) => {
186                            let left = Value::Array(array_left);
187                            let right = Value::Concat(concat);
188                            Value::delay_replacement([left, right])
189                        }
190                        right => right,
191                    }
192                }
193                Value::AddAssign(add_assign) => {
194                    let inner: Value = add_assign.into();
195                    let unmerged = inner.is_unmerged();
196                    array_left.push(RefCell::new(inner));
197                    if unmerged {
198                        array_left.as_unmerged()
199                    }
200                    Value::array(array_left)
201                }
202                right => right,
203            },
204            Value::Null => match right {
205                Value::AddAssign(_) => {
206                    return Err(Error::ConcatenateDifferentType {
207                        path: path.to_string(),
208                        left_type: "null",
209                        right_type: right.ty(),
210                    });
211                }
212                other => other,
213            },
214            // expand the first add assign to array
215            Value::None => match right {
216                Value::AddAssign(add_assign) => {
217                    let value = add_assign.try_resolve(path)?;
218                    let array = if value.is_merged() {
219                        Array::Merged(vec![RefCell::new(value)])
220                    } else {
221                        Array::Unmerged(vec![RefCell::new(value)])
222                    };
223                    Value::Array(array)
224                }
225                right => right,
226            },
227            Value::Boolean(_) | Value::String(_) | Value::Number(_) => match right {
228                // The substitution expression and concat might refer to the previous value
229                // so we cannot replace it directly
230                Value::Substitution(_) => Value::delay_replacement([left, right]),
231                Value::Concat(concat) => {
232                    // try resolve the concat at this time if it not contains substitution
233                    let right = concat.try_resolve(path)?;
234                    match right {
235                        Value::Concat(_) => Value::delay_replacement([left, right]),
236                        Value::AddAssign(_) => {
237                            return Err(Error::ConcatenateDifferentType {
238                                path: path.to_string(),
239                                left_type: left.ty(),
240                                right_type: "add_assign",
241                            });
242                        }
243                        other => other,
244                    }
245                }
246                Value::AddAssign(_) => {
247                    return Err(Error::ConcatenateDifferentType {
248                        path: path.to_string(),
249                        left_type: left.ty(),
250                        right_type: right.ty(),
251                    });
252                }
253                other => other,
254            },
255            // left value is impossible to be an add assign, because when merging two objects, the first add assign
256            // value will always expand to an array.
257            Value::AddAssign(_) => {
258                return Err(Error::ConcatenateDifferentType {
259                    path: path.to_string(),
260                    left_type: left.ty(),
261                    right_type: right.ty(),
262                });
263            }
264            Value::Substitution(_) | Value::Concat(_) | Value::DelayReplacement(_) => {
265                Value::delay_replacement([left, right])
266            }
267        };
268        trace!("replace result: `{path}`=`{new_val}`");
269        Ok(new_val)
270    }
271
272    pub(crate) fn concatenate(
273        path: &RefPath,
274        left: Value,
275        space: Option<String>,
276        right: Value,
277    ) -> crate::Result<Value> {
278        trace!("concatenate: `{}`: `{}` <- `{}`", path, left, right);
279        let val = match left {
280            Value::Object(mut left_obj) => match right {
281                Value::None => Value::object(left_obj),
282                Value::Object(right_obj) => {
283                    left_obj.merge(right_obj, Some(path))?;
284                    Value::object(left_obj)
285                }
286                Value::Null
287                | Value::Array(_)
288                | Value::Boolean(_)
289                | Value::String(_)
290                | Value::Number(_)
291                | Value::AddAssign(_) => {
292                    return Err(Error::ConcatenateDifferentType {
293                        path: path.to_string(),
294                        left_type: "object",
295                        right_type: right.ty(),
296                    });
297                }
298                Value::Substitution(_) => {
299                    let left = Value::object(left_obj);
300                    Value::concat(Concat::two(left, space, right))
301                }
302                Value::Concat(mut concat) => {
303                    let left = Value::object(left_obj);
304                    concat.push_front(RefCell::new(left), space);
305                    Value::concat(concat)
306                }
307                Value::DelayReplacement(_) => {
308                    let left = Value::object(left_obj);
309                    Value::concat(Concat::two(left, space, right))
310                }
311            },
312            Value::Array(mut left_array) => {
313                if let Value::Array(right_array) = right {
314                    left_array.extend(right_array.into_inner());
315                    Value::array(left_array)
316                } else {
317                    return Err(Error::ConcatenateDifferentType {
318                        path: path.to_string(),
319                        left_type: "array",
320                        right_type: right.ty(),
321                    });
322                }
323            }
324            Value::None => match space {
325                Some(space) => match right {
326                    Value::Null | Value::Boolean(_) | Value::String(_) | Value::Number(_) => {
327                        let mut s = String::new();
328                        s.push_str(&space);
329                        write!(&mut s, "{right}").unwrap();
330                        Value::string(s)
331                    }
332                    Value::None => Value::string(space),
333                    Value::Substitution(_) => Value::concat(Concat::two(left, Some(space), right)),
334                    right => right,
335                },
336                _ => right,
337            },
338            Value::Null | Value::Boolean(_) | Value::String(_) | Value::Number(_) => match right {
339                Value::Boolean(_) | Value::Null | Value::String(_) | Value::Number(_) => {
340                    let mut s = String::new();
341                    write!(&mut s, "{left}").unwrap();
342                    if let Some(space) = &space {
343                        s.push_str(space);
344                    }
345                    write!(&mut s, "{right}").unwrap();
346                    Value::string(s)
347                }
348                Value::None => {
349                    let mut s = String::new();
350                    write!(&mut s, "{left}").unwrap();
351                    if let Some(space) = &space {
352                        s.push_str(space);
353                    }
354                    Value::string(s)
355                }
356                Value::Substitution(_) => Value::concat(Concat::two(left, space, right)),
357                _ => {
358                    return Err(Error::ConcatenateDifferentType {
359                        path: path.to_string(),
360                        left_type: left.ty(),
361                        right_type: right.ty(),
362                    });
363                }
364            },
365            Value::Substitution(_) => Value::concat(Concat::two(left, space, right)),
366            Value::Concat(mut concat) => {
367                concat.push_back(space, RefCell::new(right));
368                Value::concat(concat)
369            }
370            Value::AddAssign(_) => {
371                return Err(Error::ConcatenateDifferentType {
372                    path: path.to_string(),
373                    left_type: left.ty(),
374                    right_type: right.ty(),
375                });
376            }
377            Value::DelayReplacement(_) => Value::concat(Concat::two(left, space, right)),
378        };
379        trace!("concatenate result: `{path}`=`{val}`");
380        debug_assert!(!matches!(
381            val,
382            Value::DelayReplacement(_) | Value::Substitution(_) | Value::AddAssign(_)
383        ));
384        Ok(val)
385    }
386
387    pub(crate) fn is_merged(&self) -> bool {
388        match self {
389            Value::Object(object) => object.is_merged(),
390            Value::Array(array) => array.is_merged(),
391            Value::Boolean(_) | Value::String(_) | Value::Number(_) | Value::Null | Value::None => {
392                true
393            }
394            Value::Substitution(_)
395            | Value::Concat(_)
396            | Value::AddAssign(_)
397            | Value::DelayReplacement(_) => false,
398        }
399    }
400
401    pub(crate) fn is_unmerged(&self) -> bool {
402        !self.is_merged()
403    }
404
405    pub(crate) fn resolve_add_assign(&mut self) {
406        if let Value::Object(object) = self {
407            object.resolve_add_assign();
408        } else if let Value::AddAssign(add_assign) = self {
409            let val = std::mem::take(&mut add_assign.0);
410            *self = Value::Array(Array::new(vec![RefCell::new(*val)]));
411            self.try_become_merged();
412        }
413    }
414
415    pub(crate) fn resolve(&mut self) -> crate::Result<()> {
416        if let Value::Object(object) = self {
417            object.substitute()?;
418        }
419        self.resolve_add_assign();
420        self.try_become_merged();
421        Ok(())
422    }
423
424    pub(crate) fn from_raw(
425        parent: Option<&RefPath>,
426        raw: crate::raw::raw_value::RawValue,
427    ) -> crate::Result<Self> {
428        let mut value = match raw {
429            crate::raw::raw_value::RawValue::Object(raw_object) => {
430                let object = Object::from_raw(parent, raw_object)?;
431                Value::object(object)
432            }
433            crate::raw::raw_value::RawValue::Array(raw_array) => {
434                let array = Array::from_raw(parent, raw_array)?;
435                Value::array(array)
436            }
437            crate::raw::raw_value::RawValue::Boolean(b) => Value::Boolean(b),
438            crate::raw::raw_value::RawValue::Null => Value::Null,
439            crate::raw::raw_value::RawValue::String(raw_string) => {
440                Value::string(raw_string.to_string())
441            }
442            crate::raw::raw_value::RawValue::Number(number) => Value::number(number),
443            crate::raw::raw_value::RawValue::Substitution(substitution) => {
444                Value::substitution(substitution)
445            }
446            crate::raw::raw_value::RawValue::Concat(concat) => {
447                let concat = Concat::from_raw(parent, concat)?;
448                Value::concat(concat)
449            }
450            crate::raw::raw_value::RawValue::AddAssign(add_assign) => {
451                let add_assign = AddAssign::from_raw(parent, add_assign)?;
452                Value::add_assign(add_assign)
453            }
454        };
455        value.try_become_merged();
456        Ok(value)
457    }
458}
459
460impl Display for Value {
461    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
462        match self {
463            Value::Object(object) => write!(f, "{object}"),
464            Value::Array(array) => write!(f, "{array}"),
465            Value::Boolean(boolean) => write!(f, "{boolean}"),
466            Value::None => write!(f, "none"),
467            Value::Null => write!(f, "null"),
468            Value::String(string) => write!(f, "{string}"),
469            Value::Number(number) => write!(f, "{number}"),
470            Value::Substitution(substitution) => write!(f, "{substitution}"),
471            Value::Concat(concat) => write!(f, "{concat}"),
472            Value::AddAssign(add_assign) => write!(f, "{add_assign}"),
473            Value::DelayReplacement(delay_merge) => write!(f, "{delay_merge}"),
474        }
475    }
476}