use serde_json::Value;
fn parse_segments(path: &str) -> Vec<String> {
let mut segments = Vec::new();
let mut current = String::new();
for c in path.chars() {
match c {
'.' | '[' | ']' => {
if !current.is_empty() {
segments.push(std::mem::take(&mut current));
}
}
_ => current.push(c),
}
}
if !current.is_empty() {
segments.push(current);
}
segments
}
pub fn extract(mut current: Value, path: &str) -> Option<Value> {
for segment in parse_segments(path) {
if let Value::String(ref s) = current {
if let Ok(parsed) = serde_json::from_str::<Value>(s) {
current = parsed;
} else {
return None;
}
}
match current {
Value::Object(mut map) => {
current = map.remove(&segment)?;
}
Value::Array(mut vec) => {
let idx: usize = segment.parse().ok()?;
if idx < vec.len() {
current = vec.swap_remove(idx);
} else {
return None;
}
}
_ => return None,
}
}
Some(current)
}
pub fn set_at_path(root: Value, path: &str, new_value: Value) -> Value {
if path.is_empty() {
return new_value;
}
let segments = parse_segments(path);
set_recursive(root, &segments, new_value)
}
fn set_recursive(current: Value, segments: &[String], new_value: Value) -> Value {
if segments.is_empty() {
return new_value;
}
let segment = &segments[0];
let rest = &segments[1..];
if let Ok(idx) = segment.parse::<usize>() {
let mut arr = if let Value::Array(a) = current {
a
} else {
vec![]
};
while arr.len() <= idx {
arr.push(Value::Null);
}
let child = std::mem::replace(&mut arr[idx], Value::Null);
arr[idx] = set_recursive(child, rest, new_value);
Value::Array(arr)
} else {
let mut obj = if let Value::Object(m) = current {
m
} else {
serde_json::Map::new()
};
let child = obj.remove(segment).unwrap_or(Value::Null);
let new_child = set_recursive(child, rest, new_value);
obj.insert(segment.clone(), new_child);
Value::Object(obj)
}
}