use serde_json::Value;
pub fn resolve<'a>(value: &'a Value, path: &str) -> Option<&'a Value> {
if path.is_empty() {
return Some(value);
}
let mut current = value;
for segment in path.split('.') {
if segment.is_empty() {
return None;
}
match current {
Value::Object(map) => {
current = map.get(segment)?;
}
Value::Array(arr) => {
let idx: usize = segment.parse().ok()?;
current = arr.get(idx)?;
}
_ => return None,
}
}
Some(current)
}
pub fn stringify(value: &Value) -> String {
match value {
Value::Null => String::new(),
Value::Bool(b) => b.to_string(),
Value::Number(n) => n.to_string(),
Value::String(s) => s.clone(),
Value::Array(_) | Value::Object(_) => value.to_string(),
}
}
pub fn csv_quote(cell: &str) -> String {
let needs_quoting = cell
.chars()
.any(|c| c == ',' || c == '"' || c == '\n' || c == '\r');
if !needs_quoting {
return cell.to_string();
}
let escaped = cell.replace('"', "\"\"");
format!("\"{escaped}\"")
}
pub fn resolve_as_string(value: &Value, path: &str) -> String {
resolve(value, path).map(stringify).unwrap_or_default()
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn resolves_top_level_field() {
let v = json!({ "name": "gpu0", "index": 0 });
assert_eq!(resolve_as_string(&v, "name"), "gpu0");
assert_eq!(resolve_as_string(&v, "index"), "0");
}
#[test]
fn missing_path_is_empty() {
let v = json!({ "name": "gpu0" });
assert_eq!(resolve_as_string(&v, "bogus"), "");
assert_eq!(resolve_as_string(&v, "name.deep"), "");
assert_eq!(resolve_as_string(&v, ""), v.to_string());
}
#[test]
fn resolves_nested_object() {
let v = json!({ "detail": { "cuda_version": "12.4" } });
assert_eq!(resolve_as_string(&v, "detail.cuda_version"), "12.4");
assert_eq!(resolve_as_string(&v, "detail.missing"), "");
}
#[test]
fn resolves_array_index() {
let v = json!({ "cores": [1, 2, 3] });
assert_eq!(resolve_as_string(&v, "cores.0"), "1");
assert_eq!(resolve_as_string(&v, "cores.2"), "3");
assert_eq!(resolve_as_string(&v, "cores.10"), "");
}
#[test]
fn null_renders_as_empty() {
let v = json!({ "optional": null });
assert_eq!(resolve_as_string(&v, "optional"), "");
assert!(resolve(&v, "optional").is_some());
}
#[test]
fn bool_and_number_render_without_quotes() {
let v = json!({ "active": true, "temp": 42.5 });
assert_eq!(resolve_as_string(&v, "active"), "true");
assert_eq!(resolve_as_string(&v, "temp"), "42.5");
}
#[test]
fn array_and_object_render_as_compact_json() {
let v = json!({ "tags": ["a", "b"], "labels": { "k": "v" } });
assert_eq!(resolve_as_string(&v, "tags"), "[\"a\",\"b\"]");
assert_eq!(resolve_as_string(&v, "labels"), "{\"k\":\"v\"}");
}
#[test]
fn csv_quote_passes_through_simple_strings() {
assert_eq!(csv_quote("plain"), "plain");
assert_eq!(csv_quote("42"), "42");
assert_eq!(csv_quote(""), "");
}
#[test]
fn csv_quote_wraps_and_escapes_special_chars() {
assert_eq!(csv_quote("has,comma"), "\"has,comma\"");
assert_eq!(csv_quote("has\"quote"), "\"has\"\"quote\"");
assert_eq!(csv_quote("has\nnewline"), "\"has\nnewline\"");
assert_eq!(csv_quote("has\rcr"), "\"has\rcr\"");
}
#[test]
fn malformed_path_yields_empty() {
let v = json!({ "x": 1 });
assert_eq!(resolve_as_string(&v, "x."), "");
assert_eq!(resolve_as_string(&v, "x..y"), "");
}
}