fuzzy-from-json-value 0.1.0

todo: write a description here
Documentation
// ---------------- [ File: fuzzy-from-json-value/src/access.rs ]
crate::ix!();

use serde_json::{Map,Value};

// -----------------------------------------------------------------
// 3) Helper macros or fns for reading fields from a Map
// -----------------------------------------------------------------

/// Safely read a string field from `obj`, or fail if missing or not a string.
pub fn get_string_field(
    obj: &Map<String, Value>,
    field: &'static str,
    target: &'static str,
) -> Result<String, FuzzyFromJsonValueError> {
    match obj.get(field) {
        Some(Value::String(s)) => Ok(s.clone()),
        Some(other) => Err(FuzzyFromJsonValueError::Other {
            target_type: target,
            detail: format!("Field '{}' must be string, got: {:?}", field, other),
        }),
        None => Err(FuzzyFromJsonValueError::MissingField {
            field_name: field,
            target_type: target,
        }),
    }
}

/// Safely read a floating‐point field from `obj`, or fail if missing or not a number.
pub fn get_f64_field(
    obj: &Map<String, Value>,
    field: &'static str,
    target: &'static str,
) -> Result<f64, FuzzyFromJsonValueError> {
    match obj.get(field) {
        Some(Value::Number(num)) => {
            match num.as_f64() {
                Some(n) => Ok(n),
                None => Err(FuzzyFromJsonValueError::Other {
                    target_type: target,
                    detail: format!("Field '{}' must be f64, got: {:?}", field, num),
                })
            }
        }
        Some(other) => Err(FuzzyFromJsonValueError::Other {
            target_type: target,
            detail: format!("Field '{}' must be number, got: {:?}", field, other),
        }),
        None => Err(FuzzyFromJsonValueError::MissingField {
            field_name: field,
            target_type: target,
        }),
    }
}

/// Like above but optional. If missing, returns None. If present and not f64, error.
pub fn get_opt_f64_field(
    obj: &Map<String, Value>,
    field: &'static str,
    _target: &'static str,
) -> Result<Option<f64>, FuzzyFromJsonValueError> {
    match obj.get(field) {
        None => Ok(None),
        Some(Value::Null) => Ok(None),
        Some(Value::Number(num)) => {
            Ok(num.as_f64())
        }
        _ => Ok(None), // or error if you want
    }
}

/// If "fields" is present and an object, flatten it. (As you do in `flatten_fields_if_present`.)
pub fn flatten_fields_if_present(value: &mut Value) {
    if let Value::Object(obj) = value {
        if let Some(fields_val) = obj.remove("fields") {
            if let Value::Object(fields_map) = fields_val {
                for (k, v) in fields_map {
                    obj.insert(k, v);
                }
            } else {
                // put it back
                obj.insert("fields".to_string(), fields_val);
            }
        }
        // Recurse
        for (_k, v) in obj.iter_mut() {
            flatten_fields_if_present(v);
        }
    } else if let Value::Array(arr) = value {
        for elem in arr {
            flatten_fields_if_present(elem);
        }
    }
}