capability-core-string-skeleton 0.1.0

A Rust crate providing a framework to generate and manipulate skill tree skeletons using string-based node representations. It aggregates dispatch and leaf holder nodes into scalable domain models.
Documentation
// ---------------- [ File: capability-core-string-skeleton/src/fuzzy_from_json_value.rs ]
crate::ix!();

impl FuzzyFromJsonValue for CoreStringSkeleton {
    fn fuzzy_from_json_value(value: &serde_json::Value) -> Result<Self, FuzzyFromJsonValueError> {
        let mut obj = match value.as_object() {
            Some(m) => m.clone(),
            None => {
                return Err(FuzzyFromJsonValueError::NotAnObject {
                    target_type: "CoreStringSkeleton",
                    actual: value.clone(),
                });
            }
        };

        flatten_fields_if_present(&mut obj);

        let bytes = match serde_json::to_vec(&serde_json::Value::Object(obj)) {
            Ok(b) => b,
            Err(e) => {
                return Err(FuzzyFromJsonValueError::Other {
                    target_type: "CoreStringSkeleton",
                    detail: format!("Could not convert object 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 Deserialize::deserialize(path_d) {
            Ok(core) => Ok(core),
            Err(path_err) => {

                warn!(
                    "Fuzzy parse for CoreStringSkeleton failed: {:?}",
                    path_err
                );
                Err(FuzzyFromJsonValueError::SerdeError {
                    target_type: "CoreStringSkeleton",
                    source: path_err,
                })
            }
        }
    }
}

//TODO: why can't we get this exact function in its actual true home? it is a duplicate
#[tracing::instrument(level = "trace", skip_all)]
fn flatten_fields_if_present(obj: &mut serde_json::Map<String, serde_json::Value>) {
    // If the JSON object contains a "fields" key and it's an object,
    // we move all keys from that sub-object up into the parent object.
    if let Some(fields_val) = obj.remove("fields") {
        if let serde_json::Value::Object(fields_map) = fields_val {
            trace!("Detected 'fields' object => flattening into top-level.");
            for (k, v) in fields_map {
                // If there's a collision, we'll just log and skip
                if obj.contains_key(&k) {
                    warn!("While flattening 'fields', key '{}' already exists in top-level => skipping overwrite.", k);
                    continue;
                }
                obj.insert(k, v);
            }
        } else {
            debug!("Key 'fields' is present but not an object => putting it back into top-level as 'fields'.");
            obj.insert("fields".to_string(), fields_val);
        }
    } else {
        trace!("No 'fields' key found => nothing to flatten.");
    }
}