1crate::ix!();
3
4fn parse_ordering_if_present(
5 obj: &serde_json::Map<String, serde_json::Value>,
6) -> Result<Option<JustifiedSubBranchOrdering>, FuzzyFromJsonValueError> {
7 if let Some(order_val) = obj.get("ordering") {
8 trace!("(parse_ordering_if_present) Found 'ordering' => unify complex_enum if needed => parse with JustifiedSubBranchOrdering");
9 let mut cloned = order_val.clone();
10 unify_complex_enum_single_variant_inplace(&mut cloned);
11
12 let parsed = JustifiedSubBranchOrdering::fuzzy_from_json_value(&cloned)
13 .map_err(|e| FuzzyFromJsonValueError::Other {
14 target_type: "Dispatch/LeafHolder/Aggregate: ordering",
15 detail: e.to_string(),
16 })?;
17
18 Ok(Some(parsed))
19 } else {
20 debug!("(parse_ordering_if_present) No 'ordering' => returning None");
21 Ok(None)
22 }
23}
24
25fn maybe_unify_internal_variant(obj: &mut Map<String, Value>) -> Option<String> {
35 if let (Some(Value::String(var_name)), Some(Value::String(_variant_type))) =
37 (obj.get("variant_name"), obj.get("variant_type"))
38 {
39 let tag = var_name.clone();
41
42 let meta_confidence = obj.remove("variant_confidence");
44 let meta_docs = obj.remove("variant_docs");
45 let meta_justification= obj.remove("variant_justification");
46 let meta_type = obj.remove("variant_type");
47 obj.remove("variant_name");
49
50 let mut inner = Map::new();
52 for (k,v) in obj.iter() {
53 inner.insert(k.to_string(), v.clone());
54 }
55
56 if let Some(v) = meta_confidence { inner.insert("variant_confidence".into(), v); }
58 if let Some(v) = meta_docs { inner.insert("variant_docs".into(), v); }
59 if let Some(v) = meta_justification { inner.insert("variant_justification".into(), v); }
60 if let Some(v) = meta_type { inner.insert("variant_type".into(), v); }
61
62 obj.clear();
64 obj.insert(tag.clone(), Value::Object(inner));
65
66 return Some(tag);
67 }
68 None
69}
70
71fn maybe_unify_single_variant_any_keys(obj: &mut Map<String, Value>) {
72 let mut old_obj = mem::take(obj);
73
74 let var_name = match old_obj.remove("variant_name") {
75 Some(Value::String(name)) => name,
76 _ => {
77 *obj = old_obj;
78 return;
79 }
80 };
81
82 let merged_map = old_obj;
83
84 let mut new_top = Map::new();
85 new_top.insert(var_name.clone(), Value::Object(merged_map));
86
87 *obj = new_top;
88
89 trace!(
90 "maybe_unify_single_variant_any_keys => replaced with externally-tagged '{}'",
91 var_name
92 );
93}
94
95fn maybe_unify_one_complex_enum(obj: &mut Map<String, Value>) {
99 let old_obj = mem::take(obj);
101
102 let is_complex_enum = old_obj
104 .get("type")
105 .and_then(|v| v.as_str())
106 .map_or(false, |s| s == "complex_enum");
107 if !is_complex_enum {
108 *obj = old_obj;
109 return;
110 }
111
112 let variants_arr = match old_obj.get("variants").and_then(|v| v.as_array()) {
113 Some(arr) => arr,
114 None => {
115 *obj = old_obj;
116 return;
117 }
118 };
119
120 if variants_arr.len() != 1 {
121 *obj = old_obj;
122 return;
123 }
124
125 let single_val = &variants_arr[0];
126 let single_obj = match single_val.as_object() {
127 Some(o) => o,
128 None => {
129 *obj = old_obj;
130 return;
131 }
132 };
133
134 let var_name = single_obj
135 .get("variant_name")
136 .and_then(|v| v.as_str())
137 .unwrap_or("UNKNOWN_VARIANT");
138
139 let mut merged_map = Map::new();
143
144 if let Some(Value::Object(fields_map)) = single_obj.get("fields") {
146 for (k, v) in fields_map {
147 merged_map.insert(k.clone(), v.clone());
148 }
149 }
150
151 for (k, v) in single_obj {
153 if k == "fields" || k == "variant_name" {
154 continue;
155 }
156 merged_map.insert(k.clone(), v.clone());
157 }
158
159 let mut new_top = Map::new();
161 new_top.insert(var_name.to_string(), Value::Object(merged_map));
162
163 *obj = new_top;
164 trace!(
165 "maybe_unify_one_complex_enum => replaced top-level with externally-tagged '{}'",
166 var_name
167 );
168}
169
170pub fn unify_complex_enum_single_variant_inplace(value: &mut Value) {
172 match value {
173 Value::Object(obj) => {
174 maybe_unify_one_complex_enum(obj);
176 maybe_unify_single_variant_from_fields(obj);
178 maybe_unify_single_variant_any_keys(obj);
180
181 if let Value::Object(o2) = value {
183 for child in o2.values_mut() {
184 unify_complex_enum_single_variant_inplace(child);
185 }
186 }
187 }
188 Value::Array(arr) => {
189 for elem in arr {
190 unify_complex_enum_single_variant_inplace(elem);
191 }
192 }
193 _ => {}
194 }
195}
196
197fn maybe_unify_single_variant_from_fields(obj: &mut Map<String, Value>) {
198 let mut old_obj = mem::take(obj);
199 let original = old_obj.clone();
200
201 let var_name = match old_obj.remove("variant_name") {
202 Some(Value::String(name)) => name,
203 _ => {
204 *obj = original;
205 return;
206 }
207 };
208
209 let fields_map = match old_obj.remove("fields") {
210 Some(Value::Object(m)) => m,
211 _ => {
212 *obj = original;
213 return;
214 }
215 };
216
217 let mut merged_map = Map::new();
218 for (k, v) in fields_map {
219 merged_map.insert(k, v);
220 }
221 for (k, v) in old_obj {
222 merged_map.insert(k, v);
223 }
224
225 let mut new_top = Map::new();
226 new_top.insert(var_name.clone(), Value::Object(merged_map));
227
228 *obj = new_top;
229
230 trace!(
231 "maybe_unify_single_variant_from_fields => replaced with externally-tagged '{}'",
232 var_name
233 );
234}
235
236fn maybe_unwrap_nested_template(obj: &mut serde_json::Map<String, serde_json::Value>) {
240 if let Some(nested_val) = obj.remove("nested_template") {
242 if let Some(nested_obj) = nested_val.as_object() {
243 for (k, v) in nested_obj {
244 obj.insert(k.clone(), v.clone());
248 }
249 } else {
250 obj.insert("nested_template".to_owned(), nested_val);
252 }
253 }
254
255 maybe_unwrap_name_field(obj);
257
258 if let Some(instr_val) = obj.remove("generation_instructions") {
260 if let Some(instr_str) = instr_val.as_str() {
262 let existing_just = obj
263 .get("variant_justification")
264 .and_then(|v| v.as_str())
265 .unwrap_or_default()
266 .to_string();
267
268 let combined_just = if existing_just.is_empty() {
269 instr_str.to_owned()
270 } else {
271 format!("{}; generation_instructions: {}", existing_just, instr_str)
272 };
273
274 obj.insert(
275 "variant_justification".to_owned(),
276 serde_json::Value::String(combined_just),
277 );
278 }
279 }
280}
281
282fn maybe_unwrap_name_field(obj: &mut serde_json::Map<String, serde_json::Value>) {
283 if let Some(name_val) = obj.get_mut("name") {
287 if let Some(m) = name_val.as_object_mut() {
288 if let Some(Value::String(typ_s)) = m.get("type") {
291 if typ_s == "string" {
292 if let Some(Value::String(the_value)) = m.get("value") {
293 let new_str = the_value.clone();
295 *name_val = Value::String(new_str);
296 }
297 }
298 }
299 }
300 }
301}
302
303impl FuzzyFromJsonValue for JustifiedStringSkeletonNode {
304 fn fuzzy_from_json_value(value: &serde_json::Value)
305 -> Result<Self, FuzzyFromJsonValueError>
306 {
307 trace!("(JustifiedStringSkeletonNode) Entering fuzzy_from_json_value => {}", value);
308
309 let mut cloned = value.clone();
311 if let Some(obj) = cloned.as_object_mut() {
312 maybe_unwrap_nested_template(obj);
313 }
314 unify_complex_enum_single_variant_inplace(&mut cloned);
315
316 let obj = match cloned.as_object() {
318 Some(m) => {
319 trace!("(JustifiedStringSkeletonNode) Flattened shape => proceed with variant detection");
320 m
321 }
322 None => {
323 error!("(JustifiedStringSkeletonNode) Not an object => fail");
324 return Err(FuzzyFromJsonValueError::NotAnObject {
325 target_type: "JustifiedStringSkeletonNode",
326 actual: cloned,
327 });
328 }
329 };
330
331 let all_keys_vec: Vec<String> = obj.keys().map(|k| k.to_string()).collect();
332 trace!("(JustifiedStringSkeletonNode) top-level keys => {:?}", all_keys_vec);
333
334 let mut found_variants = Vec::new();
336 for candidate in ["Dispatch","LeafHolder","Aggregate"] {
337 if obj.contains_key(candidate) {
338 found_variants.push(candidate);
339 }
340 }
341 trace!("(JustifiedStringSkeletonNode) found_variants={:?}", found_variants);
342
343 if found_variants.len() != 1 {
344 error!(
345 "(JustifiedStringSkeletonNode) expected exactly 1 of [Dispatch,LeafHolder,Aggregate], found={:?}",
346 found_variants
347 );
348 return Err(FuzzyFromJsonValueError::Other {
349 target_type: "JustifiedStringSkeletonNode",
350 detail: format!(
351 "Expected exactly 1 of [Dispatch,LeafHolder,Aggregate], found={:?}, keys={:?}",
352 found_variants, all_keys_vec
353 ),
354 });
355 }
356
357 let variant_name = found_variants[0];
358 let variant_val = obj.get(variant_name).expect("logic bug in found_variants");
359 let inner_obj = match variant_val.as_object() {
360 Some(m) => m,
361 None => {
362 error!(
363 "(JustifiedStringSkeletonNode) variant '{}' => must be object => got {:?}",
364 variant_name, variant_val
365 );
366 return Err(FuzzyFromJsonValueError::Other {
367 target_type: "JustifiedStringSkeletonNode",
368 detail: format!("Variant '{}' must map to an object, got {:?}", variant_name, variant_val),
369 });
370 }
371 };
372
373 let ordering_parsed = parse_ordering_if_present(inner_obj)?;
375
376 match variant_name {
378 "Dispatch" => {
379 trace!("(JustifiedStringSkeletonNode) => Dispatch");
380 let variant_conf = get_f64_field(inner_obj, "variant_confidence", "Dispatch")
381 .unwrap_or(0.0);
382 let variant_just = get_string_field(inner_obj, "variant_justification", "Dispatch")
383 .unwrap_or_default();
384
385 let name_val = get_string_field(inner_obj, "name", "Dispatch")?;
386 let name_conf = get_f64_field(inner_obj, "name_confidence", "Dispatch")
387 .unwrap_or(0.0);
388 let name_just = get_string_field(inner_obj, "name_justification", "Dispatch")
389 .unwrap_or_default();
390
391 let children_conf = get_f64_field(inner_obj, "children_confidence", "Dispatch")
392 .unwrap_or(0.0);
393 let children_just = get_string_field(inner_obj, "children_justification", "Dispatch")
394 .unwrap_or_default();
395
396 let mut final_children_map = HashMap::new();
398 if let Some(Value::Object(child_map)) = inner_obj.get("children") {
399 for (child_key, child_value) in child_map {
400 if child_key == "map_key_template"
402 || child_key == "map_value_template"
403 || child_key == "generation_instructions"
404 {
405 trace!("(Dispatch) Skipping metadata key='{}'", child_key);
406 continue;
407 }
408
409 trace!("(JustifiedStringSkeletonNode) Dispatch => parse child='{}' => {}", child_key, child_value);
410 let parsed_child_just = JustifiedDispatchChildSpec::fuzzy_from_json_value(child_value)
411 .map_err(|e| {
412 error!("(Dispatch) Could not parse child='{}': {:?}", child_key, e);
413 FuzzyFromJsonValueError::Other {
414 target_type: "Dispatch",
415 detail: format!("Error child='{}': {:?}", child_key, e),
416 }
417 })?;
418 final_children_map.insert(child_key.clone(), parsed_child_just.into());
419 }
420 }
421
422 trace!("(JustifiedStringSkeletonNode) => Dispatch => success => children count={}", final_children_map.len());
423
424 Ok(JustifiedStringSkeletonNode::Dispatch {
425 variant_confidence: variant_conf,
426 variant_justification: variant_just,
427 name: name_val,
428 name_confidence: name_conf,
429 name_justification: name_just,
430 ordering: ordering_parsed,
431 children: final_children_map,
432 children_confidence: children_conf,
433 children_justification: children_just,
434 })
435 }
436
437 "LeafHolder" => {
438 trace!("(JustifiedStringSkeletonNode) => LeafHolder");
439 let variant_conf = get_f64_field(inner_obj, "variant_confidence", "LeafHolder")
440 .unwrap_or(0.0);
441 let variant_just = get_string_field(inner_obj, "variant_justification", "LeafHolder")
442 .unwrap_or_default();
443
444 let name_val = get_string_field(inner_obj, "name", "LeafHolder")?;
445 let name_conf = get_f64_field(inner_obj, "name_confidence", "LeafHolder")
446 .unwrap_or(0.0);
447 let name_just = get_string_field(inner_obj, "name_justification", "LeafHolder")
448 .unwrap_or_default();
449
450 let n_leaves_val = inner_obj.get("n_leaves").ok_or_else(|| {
451 error!("(LeafHolder) Missing 'n_leaves' => fail");
452 FuzzyFromJsonValueError::MissingField {
453 field_name: "n_leaves",
454 target_type: "LeafHolder",
455 }
456 })?;
457 let n_leaves_u8 = fuzzy_u8(n_leaves_val).map_err(|msg| {
458 error!("(LeafHolder) Could not parse n_leaves => {:?}", msg);
459 FuzzyFromJsonValueError::Other {
460 target_type: "LeafHolder",
461 detail: msg.to_string(),
462 }
463 })?;
464
465 let capstone_val = inner_obj.get("capstone").ok_or_else(|| {
466 error!("(LeafHolder) Missing 'capstone' => fail");
467 FuzzyFromJsonValueError::MissingField {
468 field_name: "capstone",
469 target_type: "LeafHolder",
470 }
471 })?;
472 let capstone_bool = match capstone_val {
473 Value::Bool(b) => *b,
474 other => {
475 error!("(LeafHolder) 'capstone' must be bool => got {:?}", other);
476 return Err(FuzzyFromJsonValueError::Other {
477 target_type: "LeafHolder",
478 detail: format!("Expected 'capstone' to be bool, got {:?}", other),
479 });
480 }
481 };
482
483 trace!("(JustifiedStringSkeletonNode) => LeafHolder => success => name='{}', n_leaves={}, capstone={}",
484 name_val, n_leaves_u8, capstone_bool
485 );
486
487 Ok(JustifiedStringSkeletonNode::LeafHolder {
488 variant_confidence: variant_conf,
489 variant_justification: variant_just,
490 name: name_val,
491 name_confidence: name_conf,
492 name_justification: name_just,
493 ordering: ordering_parsed,
494 n_leaves: n_leaves_u8,
495 capstone: capstone_bool,
496 })
497 }
498
499 "Aggregate" => {
500 trace!("(JustifiedStringSkeletonNode) => Aggregate");
501 let variant_conf = get_f64_field(inner_obj, "variant_confidence", "Aggregate")
502 .unwrap_or(0.0);
503 let variant_just = get_string_field(inner_obj, "variant_justification", "Aggregate")
504 .unwrap_or_default();
505
506 let name_val = get_string_field(inner_obj, "name", "Aggregate")?;
507 let name_conf = get_f64_field(inner_obj, "name_confidence", "Aggregate")
508 .unwrap_or(0.0);
509 let name_just = get_string_field(inner_obj, "name_justification", "Aggregate")
510 .unwrap_or_default();
511
512 let children_conf = get_f64_field(inner_obj, "children_confidence", "Aggregate")
513 .unwrap_or(0.0);
514 let children_just = get_string_field(inner_obj, "children_justification", "Aggregate")
515 .unwrap_or_default();
516
517 let mut final_children_map = HashMap::new();
518 if let Some(Value::Object(child_map)) = inner_obj.get("children") {
519 for (child_key, child_value) in child_map {
520 if child_key == "map_key_template"
522 || child_key == "map_value_template"
523 || child_key == "generation_instructions"
524 {
525 trace!("(Aggregate) Skipping metadata key='{}'", child_key);
526 continue;
527 }
528
529 trace!("(Aggregate) parse child='{}' => {}", child_key, child_value);
530 let parsed_child_just = JustifiedAggregateChildSpec::fuzzy_from_json_value(child_value)
531 .map_err(|e| {
532 error!("(Aggregate) Could not parse child='{}': {:?}", child_key, e);
533 FuzzyFromJsonValueError::Other {
534 target_type: "Aggregate",
535 detail: format!("Error child='{}': {:?}", child_key, e),
536 }
537 })?;
538 final_children_map.insert(child_key.clone(), parsed_child_just.into());
539 }
540 }
541
542 trace!("(JustifiedStringSkeletonNode) => Aggregate => success => name='{}', children={}",
543 name_val, final_children_map.len()
544 );
545
546 Ok(JustifiedStringSkeletonNode::Aggregate {
547 variant_confidence: variant_conf,
548 variant_justification: variant_just,
549 name: name_val,
550 name_confidence: name_conf,
551 name_justification: name_just,
552 ordering: ordering_parsed,
553 children: final_children_map,
554 children_confidence: children_conf,
555 children_justification: children_just,
556 })
557 }
558
559 other => {
560 error!("(JustifiedStringSkeletonNode) Unexpected variant='{}'", other);
561 Err(FuzzyFromJsonValueError::Other {
562 target_type: "JustifiedStringSkeletonNode",
563 detail: format!("Unexpected variant key='{}'", other),
564 })
565 }
566 }
567 }
568}