crate::ix!();
use serde_json::Map;
fn flatten_fields_if_present_in_obj(obj: &mut Map<String, JsonValue>) {
if let Some(fields_val) = obj.remove("fields") {
if let JsonValue::Object(fields_map) = fields_val {
debug!("Flattening 'fields' object into top-level.");
for (k, v) in fields_map {
if obj.contains_key(&k) {
warn!("Collision while flattening 'fields': key '{}' already exists => skipping.", k);
} else {
obj.insert(k, v);
}
}
} else {
obj.insert("fields".to_string(), fields_val);
}
}
}
fn maybe_unwrap_meta_container(obj: &mut Map<String, JsonValue>) {
let container_kind = obj
.get("type")
.and_then(|val| val.as_str())
.map(str::to_lowercase)
.unwrap_or_default();
if !(container_kind == "array_of" || container_kind == "map_of") {
return;
}
let value_val = match obj.get("value") {
Some(v) => v.clone(),
None => return,
};
debug!("Unwrapping container (type='{}') => discarding leftover meta.", container_kind);
obj.clear();
obj.insert("value___unwrapped".to_string(), value_val);
}
fn maybe_unwrap_single_value(obj: &mut Map<String, JsonValue>) {
if obj.len() == 1 && obj.contains_key("value") {
let unwrapped = obj.remove("value").unwrap();
debug!("Unwrapping single-key object => using the child 'value' directly.");
obj.clear();
obj.insert("value___unwrapped".to_string(), unwrapped);
}
}
fn recursively_unify_annotated_leaf_meta(value: &mut JsonValue) {
match value {
JsonValue::Object(obj) => {
flatten_fields_if_present_in_obj(obj);
maybe_unwrap_meta_container(obj);
maybe_unwrap_single_value(obj);
let skip_keys = [
"generation_instructions",
"nested_template",
"required",
"type",
"variant_docs",
"map_key_template",
"map_value_template",
"struct_docs",
"struct_name",
"enum_docs",
"map_confidence",
"map_justification",
];
for &k in &skip_keys {
obj.remove(k);
}
for child_val in obj.values_mut() {
recursively_unify_annotated_leaf_meta(child_val);
}
if obj.len() == 1 && obj.contains_key("value___unwrapped") {
let unwrapped = obj.remove("value___unwrapped").unwrap();
*value = unwrapped;
}
}
JsonValue::Array(arr) => {
for elem in arr {
recursively_unify_annotated_leaf_meta(elem);
}
}
_ => {}
}
}
impl FuzzyFromJsonValue for AnnotatedLeafHolderExpansions {
fn fuzzy_from_json_value(value: &serde_json::Value) -> Result<Self, crate::FuzzyFromJsonValueError> {
trace!(
"Fuzzy parse for AnnotatedLeafHolderExpansions => raw input:\n{}",
value
);
let mut cloned = value.clone();
recursively_unify_annotated_leaf_meta(&mut cloned);
let bytes = match serde_json::to_vec(&cloned) {
Ok(b) => b,
Err(e) => {
return Err(crate::FuzzyFromJsonValueError::Other {
target_type: "AnnotatedLeafHolderExpansions",
detail: format!("Could not convert unified shape to bytes => {}", e),
});
}
};
let mut track = serde_path_to_error::Track::new();
let mut d = serde_json::Deserializer::from_slice(&bytes);
let mut path_d = serde_path_to_error::Deserializer::new(&mut d, &mut track);
match <AnnotatedLeafHolderExpansions as Deserialize>::deserialize(path_d) {
Ok(obj) => {
trace!("Parsed AnnotatedLeafHolderExpansions successfully!");
Ok(obj)
}
Err(path_err) => {
error!("Fuzzy parse for AnnotatedLeafHolderExpansions failed: {:?}", path_err);
Err(crate::FuzzyFromJsonValueError::SerdeError {
target_type: "AnnotatedLeafHolderExpansions",
source: path_err,
})
}
}
}
}
#[cfg(test)]
mod fuzzy_annotated_leaf_holder_tests {
use super::*;
use serde_json::{json, Value};
fn unify_meta(mut v: Value) -> Value {
recursively_unify_annotated_leaf_meta(&mut v);
v
}
#[test]
fn test_no_meta_fields_remains_unchanged() {
let original = json!({
"some_array": [1,2,3],
"some_object": { "inner": 42 }
});
let final_val = unify_meta(original.clone());
assert_eq!(final_val, original, "Should remain unchanged if no meta fields");
}
#[test]
fn test_flatten_fields_if_present_in_obj() {
let original = json!({
"fields": {
"foo": "bar",
"nested": 123
},
"another": "field"
});
let expected = json!({
"foo": "bar",
"nested": 123,
"another": "field"
});
let final_val = unify_meta(original);
assert_eq!(final_val, expected, "Should flatten 'fields' subobject");
}
#[test]
fn test_meta_container_array_of() {
let original = json!({
"annotated_leaf_holders": {
"type": "array_of",
"required": true,
"generation_instructions": "some instructions",
"nested_template": { "dummy": "stuff" },
"value": [
{ "leaf_holder_name": "HolderA" },
{ "leaf_holder_name": "HolderB" }
]
}
});
let expected = json!({
"annotated_leaf_holders": [
{ "leaf_holder_name": "HolderA" },
{ "leaf_holder_name": "HolderB" }
]
});
let final_val = unify_meta(original);
assert_eq!(final_val, expected, "Should unwrap 'array_of' => final array");
}
#[test]
fn test_meta_container_map_of() {
let original = json!({
"some_map": {
"type": "map_of",
"map_key_template": "string",
"map_value_template": { "generation_instructions": "..." },
"value": {
"KeyA": { "foo": "bar" },
"KeyB": { "numbers": [1,2,3] }
}
}
});
let expected = json!({
"some_map": {
"KeyA": { "foo": "bar" },
"KeyB": { "numbers": [1,2,3] }
}
});
let final_val = unify_meta(original);
assert_eq!(final_val, expected, "Should unwrap 'map_of' => final object");
}
#[test]
fn test_nested_case_fields_and_array_of() {
let original = json!({
"fields": {
"outer_meta": "some meta"
},
"some_nested": {
"type": "array_of",
"value": [
{
"fields": { "subfield": 123 },
"another": "prop"
},
{
"fields": { "hello": "world" },
"arr": [1,2]
}
],
"required": true
}
});
let expected = json!({
"outer_meta": "some meta",
"some_nested": [
{
"subfield": 123,
"another": "prop"
},
{
"hello": "world",
"arr": [1,2]
}
]
});
let final_val = unify_meta(original);
assert_eq!(final_val, expected, "Nested flatten + unwrap array_of");
}
#[test]
fn test_container_lacking_value_is_unchanged() {
let original = json!({
"weird": {
"type": "array_of",
"nested_template": {},
"fields": {}
}
});
let expected = json!({
"weird": {}
});
let final_val = unify_meta(original);
assert_eq!(final_val, expected, "No 'value' => we do not unwrap anything");
}
#[test]
fn test_collision_when_flattening_fields() {
let original = json!({
"foo": "keep me",
"fields": {
"foo": "would overwrite if we didn't skip",
"other": 999
}
});
let expected = json!({
"foo": "keep me", "other": 999 });
let final_val = unify_meta(original);
assert_eq!(final_val, expected, "Should skip collisions");
}
}