crate::ix!();
fn parse_ordering_if_present(
obj: &serde_json::Map<String, serde_json::Value>,
) -> Result<Option<JustifiedSubBranchOrdering>, FuzzyFromJsonValueError> {
if let Some(order_val) = obj.get("ordering") {
trace!("(parse_ordering_if_present) Found 'ordering' => unify complex_enum if needed => parse with JustifiedSubBranchOrdering");
let mut cloned = order_val.clone();
unify_complex_enum_single_variant_inplace(&mut cloned);
let parsed = JustifiedSubBranchOrdering::fuzzy_from_json_value(&cloned)
.map_err(|e| FuzzyFromJsonValueError::Other {
target_type: "Dispatch/LeafHolder/Aggregate: ordering",
detail: e.to_string(),
})?;
Ok(Some(parsed))
} else {
debug!("(parse_ordering_if_present) No 'ordering' => returning None");
Ok(None)
}
}
fn maybe_unify_internal_variant(obj: &mut Map<String, Value>) -> Option<String> {
if let (Some(Value::String(var_name)), Some(Value::String(_variant_type))) =
(obj.get("variant_name"), obj.get("variant_type"))
{
let tag = var_name.clone();
let meta_confidence = obj.remove("variant_confidence");
let meta_docs = obj.remove("variant_docs");
let meta_justification= obj.remove("variant_justification");
let meta_type = obj.remove("variant_type");
obj.remove("variant_name");
let mut inner = Map::new();
for (k,v) in obj.iter() {
inner.insert(k.to_string(), v.clone());
}
if let Some(v) = meta_confidence { inner.insert("variant_confidence".into(), v); }
if let Some(v) = meta_docs { inner.insert("variant_docs".into(), v); }
if let Some(v) = meta_justification { inner.insert("variant_justification".into(), v); }
if let Some(v) = meta_type { inner.insert("variant_type".into(), v); }
obj.clear();
obj.insert(tag.clone(), Value::Object(inner));
return Some(tag);
}
None
}
fn maybe_unify_single_variant_any_keys(obj: &mut Map<String, Value>) {
let mut old_obj = mem::take(obj);
let var_name = match old_obj.remove("variant_name") {
Some(Value::String(name)) => name,
_ => {
*obj = old_obj;
return;
}
};
let merged_map = old_obj;
let mut new_top = Map::new();
new_top.insert(var_name.clone(), Value::Object(merged_map));
*obj = new_top;
trace!(
"maybe_unify_single_variant_any_keys => replaced with externally-tagged '{}'",
var_name
);
}
fn maybe_unify_one_complex_enum(obj: &mut Map<String, Value>) {
let old_obj = mem::take(obj);
let is_complex_enum = old_obj
.get("type")
.and_then(|v| v.as_str())
.map_or(false, |s| s == "complex_enum");
if !is_complex_enum {
*obj = old_obj;
return;
}
let variants_arr = match old_obj.get("variants").and_then(|v| v.as_array()) {
Some(arr) => arr,
None => {
*obj = old_obj;
return;
}
};
if variants_arr.len() != 1 {
*obj = old_obj;
return;
}
let single_val = &variants_arr[0];
let single_obj = match single_val.as_object() {
Some(o) => o,
None => {
*obj = old_obj;
return;
}
};
let var_name = single_obj
.get("variant_name")
.and_then(|v| v.as_str())
.unwrap_or("UNKNOWN_VARIANT");
let mut merged_map = Map::new();
if let Some(Value::Object(fields_map)) = single_obj.get("fields") {
for (k, v) in fields_map {
merged_map.insert(k.clone(), v.clone());
}
}
for (k, v) in single_obj {
if k == "fields" || k == "variant_name" {
continue;
}
merged_map.insert(k.clone(), v.clone());
}
let mut new_top = Map::new();
new_top.insert(var_name.to_string(), Value::Object(merged_map));
*obj = new_top;
trace!(
"maybe_unify_one_complex_enum => replaced top-level with externally-tagged '{}'",
var_name
);
}
pub fn unify_complex_enum_single_variant_inplace(value: &mut Value) {
match value {
Value::Object(obj) => {
maybe_unify_one_complex_enum(obj);
maybe_unify_single_variant_from_fields(obj);
maybe_unify_single_variant_any_keys(obj);
if let Value::Object(o2) = value {
for child in o2.values_mut() {
unify_complex_enum_single_variant_inplace(child);
}
}
}
Value::Array(arr) => {
for elem in arr {
unify_complex_enum_single_variant_inplace(elem);
}
}
_ => {}
}
}
fn maybe_unify_single_variant_from_fields(obj: &mut Map<String, Value>) {
let mut old_obj = mem::take(obj);
let original = old_obj.clone();
let var_name = match old_obj.remove("variant_name") {
Some(Value::String(name)) => name,
_ => {
*obj = original;
return;
}
};
let fields_map = match old_obj.remove("fields") {
Some(Value::Object(m)) => m,
_ => {
*obj = original;
return;
}
};
let mut merged_map = Map::new();
for (k, v) in fields_map {
merged_map.insert(k, v);
}
for (k, v) in old_obj {
merged_map.insert(k, v);
}
let mut new_top = Map::new();
new_top.insert(var_name.clone(), Value::Object(merged_map));
*obj = new_top;
trace!(
"maybe_unify_single_variant_from_fields => replaced with externally-tagged '{}'",
var_name
);
}
fn maybe_unwrap_nested_template(obj: &mut serde_json::Map<String, serde_json::Value>) {
if let Some(nested_val) = obj.remove("nested_template") {
if let Some(nested_obj) = nested_val.as_object() {
for (k, v) in nested_obj {
obj.insert(k.clone(), v.clone());
}
} else {
obj.insert("nested_template".to_owned(), nested_val);
}
}
maybe_unwrap_name_field(obj);
if let Some(instr_val) = obj.remove("generation_instructions") {
if let Some(instr_str) = instr_val.as_str() {
let existing_just = obj
.get("variant_justification")
.and_then(|v| v.as_str())
.unwrap_or_default()
.to_string();
let combined_just = if existing_just.is_empty() {
instr_str.to_owned()
} else {
format!("{}; generation_instructions: {}", existing_just, instr_str)
};
obj.insert(
"variant_justification".to_owned(),
serde_json::Value::String(combined_just),
);
}
}
}
fn maybe_unwrap_name_field(obj: &mut serde_json::Map<String, serde_json::Value>) {
if let Some(name_val) = obj.get_mut("name") {
if let Some(m) = name_val.as_object_mut() {
if let Some(Value::String(typ_s)) = m.get("type") {
if typ_s == "string" {
if let Some(Value::String(the_value)) = m.get("value") {
let new_str = the_value.clone();
*name_val = Value::String(new_str);
}
}
}
}
}
}
impl FuzzyFromJsonValue for JustifiedStringSkeletonNode {
fn fuzzy_from_json_value(value: &serde_json::Value)
-> Result<Self, FuzzyFromJsonValueError>
{
trace!("(JustifiedStringSkeletonNode) Entering fuzzy_from_json_value => {}", value);
let mut cloned = value.clone();
if let Some(obj) = cloned.as_object_mut() {
maybe_unwrap_nested_template(obj);
}
unify_complex_enum_single_variant_inplace(&mut cloned);
let obj = match cloned.as_object() {
Some(m) => {
trace!("(JustifiedStringSkeletonNode) Flattened shape => proceed with variant detection");
m
}
None => {
error!("(JustifiedStringSkeletonNode) Not an object => fail");
return Err(FuzzyFromJsonValueError::NotAnObject {
target_type: "JustifiedStringSkeletonNode",
actual: cloned,
});
}
};
let all_keys_vec: Vec<String> = obj.keys().map(|k| k.to_string()).collect();
trace!("(JustifiedStringSkeletonNode) top-level keys => {:?}", all_keys_vec);
let mut found_variants = Vec::new();
for candidate in ["Dispatch","LeafHolder","Aggregate"] {
if obj.contains_key(candidate) {
found_variants.push(candidate);
}
}
trace!("(JustifiedStringSkeletonNode) found_variants={:?}", found_variants);
if found_variants.len() != 1 {
error!(
"(JustifiedStringSkeletonNode) expected exactly 1 of [Dispatch,LeafHolder,Aggregate], found={:?}",
found_variants
);
return Err(FuzzyFromJsonValueError::Other {
target_type: "JustifiedStringSkeletonNode",
detail: format!(
"Expected exactly 1 of [Dispatch,LeafHolder,Aggregate], found={:?}, keys={:?}",
found_variants, all_keys_vec
),
});
}
let variant_name = found_variants[0];
let variant_val = obj.get(variant_name).expect("logic bug in found_variants");
let inner_obj = match variant_val.as_object() {
Some(m) => m,
None => {
error!(
"(JustifiedStringSkeletonNode) variant '{}' => must be object => got {:?}",
variant_name, variant_val
);
return Err(FuzzyFromJsonValueError::Other {
target_type: "JustifiedStringSkeletonNode",
detail: format!("Variant '{}' must map to an object, got {:?}", variant_name, variant_val),
});
}
};
let ordering_parsed = parse_ordering_if_present(inner_obj)?;
match variant_name {
"Dispatch" => {
trace!("(JustifiedStringSkeletonNode) => Dispatch");
let variant_conf = get_f64_field(inner_obj, "variant_confidence", "Dispatch")
.unwrap_or(0.0);
let variant_just = get_string_field(inner_obj, "variant_justification", "Dispatch")
.unwrap_or_default();
let name_val = get_string_field(inner_obj, "name", "Dispatch")?;
let name_conf = get_f64_field(inner_obj, "name_confidence", "Dispatch")
.unwrap_or(0.0);
let name_just = get_string_field(inner_obj, "name_justification", "Dispatch")
.unwrap_or_default();
let children_conf = get_f64_field(inner_obj, "children_confidence", "Dispatch")
.unwrap_or(0.0);
let children_just = get_string_field(inner_obj, "children_justification", "Dispatch")
.unwrap_or_default();
let mut final_children_map = HashMap::new();
if let Some(Value::Object(child_map)) = inner_obj.get("children") {
for (child_key, child_value) in child_map {
if child_key == "map_key_template"
|| child_key == "map_value_template"
|| child_key == "generation_instructions"
{
trace!("(Dispatch) Skipping metadata key='{}'", child_key);
continue;
}
trace!("(JustifiedStringSkeletonNode) Dispatch => parse child='{}' => {}", child_key, child_value);
let parsed_child_just = JustifiedDispatchChildSpec::fuzzy_from_json_value(child_value)
.map_err(|e| {
error!("(Dispatch) Could not parse child='{}': {:?}", child_key, e);
FuzzyFromJsonValueError::Other {
target_type: "Dispatch",
detail: format!("Error child='{}': {:?}", child_key, e),
}
})?;
final_children_map.insert(child_key.clone(), parsed_child_just.into());
}
}
trace!("(JustifiedStringSkeletonNode) => Dispatch => success => children count={}", final_children_map.len());
Ok(JustifiedStringSkeletonNode::Dispatch {
variant_confidence: variant_conf,
variant_justification: variant_just,
name: name_val,
name_confidence: name_conf,
name_justification: name_just,
ordering: ordering_parsed,
children: final_children_map,
children_confidence: children_conf,
children_justification: children_just,
})
}
"LeafHolder" => {
trace!("(JustifiedStringSkeletonNode) => LeafHolder");
let variant_conf = get_f64_field(inner_obj, "variant_confidence", "LeafHolder")
.unwrap_or(0.0);
let variant_just = get_string_field(inner_obj, "variant_justification", "LeafHolder")
.unwrap_or_default();
let name_val = get_string_field(inner_obj, "name", "LeafHolder")?;
let name_conf = get_f64_field(inner_obj, "name_confidence", "LeafHolder")
.unwrap_or(0.0);
let name_just = get_string_field(inner_obj, "name_justification", "LeafHolder")
.unwrap_or_default();
let n_leaves_val = inner_obj.get("n_leaves").ok_or_else(|| {
error!("(LeafHolder) Missing 'n_leaves' => fail");
FuzzyFromJsonValueError::MissingField {
field_name: "n_leaves",
target_type: "LeafHolder",
}
})?;
let n_leaves_u8 = fuzzy_u8(n_leaves_val).map_err(|msg| {
error!("(LeafHolder) Could not parse n_leaves => {:?}", msg);
FuzzyFromJsonValueError::Other {
target_type: "LeafHolder",
detail: msg.to_string(),
}
})?;
let capstone_val = inner_obj.get("capstone").ok_or_else(|| {
error!("(LeafHolder) Missing 'capstone' => fail");
FuzzyFromJsonValueError::MissingField {
field_name: "capstone",
target_type: "LeafHolder",
}
})?;
let capstone_bool = match capstone_val {
Value::Bool(b) => *b,
other => {
error!("(LeafHolder) 'capstone' must be bool => got {:?}", other);
return Err(FuzzyFromJsonValueError::Other {
target_type: "LeafHolder",
detail: format!("Expected 'capstone' to be bool, got {:?}", other),
});
}
};
trace!("(JustifiedStringSkeletonNode) => LeafHolder => success => name='{}', n_leaves={}, capstone={}",
name_val, n_leaves_u8, capstone_bool
);
Ok(JustifiedStringSkeletonNode::LeafHolder {
variant_confidence: variant_conf,
variant_justification: variant_just,
name: name_val,
name_confidence: name_conf,
name_justification: name_just,
ordering: ordering_parsed,
n_leaves: n_leaves_u8,
capstone: capstone_bool,
})
}
"Aggregate" => {
trace!("(JustifiedStringSkeletonNode) => Aggregate");
let variant_conf = get_f64_field(inner_obj, "variant_confidence", "Aggregate")
.unwrap_or(0.0);
let variant_just = get_string_field(inner_obj, "variant_justification", "Aggregate")
.unwrap_or_default();
let name_val = get_string_field(inner_obj, "name", "Aggregate")?;
let name_conf = get_f64_field(inner_obj, "name_confidence", "Aggregate")
.unwrap_or(0.0);
let name_just = get_string_field(inner_obj, "name_justification", "Aggregate")
.unwrap_or_default();
let children_conf = get_f64_field(inner_obj, "children_confidence", "Aggregate")
.unwrap_or(0.0);
let children_just = get_string_field(inner_obj, "children_justification", "Aggregate")
.unwrap_or_default();
let mut final_children_map = HashMap::new();
if let Some(Value::Object(child_map)) = inner_obj.get("children") {
for (child_key, child_value) in child_map {
if child_key == "map_key_template"
|| child_key == "map_value_template"
|| child_key == "generation_instructions"
{
trace!("(Aggregate) Skipping metadata key='{}'", child_key);
continue;
}
trace!("(Aggregate) parse child='{}' => {}", child_key, child_value);
let parsed_child_just = JustifiedAggregateChildSpec::fuzzy_from_json_value(child_value)
.map_err(|e| {
error!("(Aggregate) Could not parse child='{}': {:?}", child_key, e);
FuzzyFromJsonValueError::Other {
target_type: "Aggregate",
detail: format!("Error child='{}': {:?}", child_key, e),
}
})?;
final_children_map.insert(child_key.clone(), parsed_child_just.into());
}
}
trace!("(JustifiedStringSkeletonNode) => Aggregate => success => name='{}', children={}",
name_val, final_children_map.len()
);
Ok(JustifiedStringSkeletonNode::Aggregate {
variant_confidence: variant_conf,
variant_justification: variant_just,
name: name_val,
name_confidence: name_conf,
name_justification: name_just,
ordering: ordering_parsed,
children: final_children_map,
children_confidence: children_conf,
children_justification: children_just,
})
}
other => {
error!("(JustifiedStringSkeletonNode) Unexpected variant='{}'", other);
Err(FuzzyFromJsonValueError::Other {
target_type: "JustifiedStringSkeletonNode",
detail: format!("Unexpected variant key='{}'", other),
})
}
}
}
}