use serde_json::{Map, Value};
fn json_value_to_string(v: &Value) -> String {
if let Some(s) = v.as_str() {
s.to_string()
} else if v.is_null() {
String::new()
} else {
v.to_string()
}
}
pub fn json_get_strings(data: &[u8], keys: &[&str]) -> Vec<String> {
let Ok(value) = serde_json::from_slice::<Value>(data) else {
return vec![String::new(); keys.len()];
};
let empty = serde_json::Map::new();
let map = value.as_object().unwrap_or(&empty);
keys.iter().map(|key| get_map_string(map, key)).collect()
}
pub fn json_get(data: &[u8], key: &str) -> String {
serde_json::from_slice::<Value>(data)
.ok()
.as_ref()
.and_then(|v| v.get(key))
.map_or(String::new(), json_value_to_string)
}
pub fn get_map_string(data: &Map<String, Value>, key: &str) -> String {
data.get(key).map_or(String::new(), json_value_to_string)
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn json_get_returns_string_value_directly() {
let json = br#"{"name": "John"}"#;
assert_eq!(json_get(json, "name"), "John");
}
#[test]
fn json_get_stringifies_non_string_values() {
let json = br#"{"age": 30, "active": true}"#;
assert_eq!(json_get(json, "age"), "30");
assert_eq!(json_get(json, "active"), "true");
}
#[test]
fn json_get_null_and_missing_return_empty() {
let json = br#"{"x": null}"#;
assert_eq!(json_get(json, "x"), "");
assert_eq!(json_get(json, "nonexistent"), "");
}
#[test]
fn json_get_invalid_json_returns_empty() {
assert_eq!(json_get(b"not json", "any"), "");
}
#[test]
fn json_get_strings_preserves_key_order_and_count() {
let json = br#"{"name": "John", "age": 30}"#;
assert_eq!(
json_get_strings(json, &["name", "age", "missing"]),
vec!["John".to_string(), "30".to_string(), String::new(),]
);
}
#[test]
fn json_get_strings_invalid_json_returns_all_empty() {
let out = json_get_strings(b"garbage", &["a", "b", "c"]);
assert_eq!(out.len(), 3);
assert!(out.iter().all(|s| s.is_empty()));
}
}