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 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 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 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 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 Value::Substitution(_) => Value::delay_replacement([left, right]),
231 Value::Concat(concat) => {
232 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 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}