use serde_json::Value;
const REDACTED: &str = "[REDACTED]";
pub fn apply_redaction(mut value: Value, paths: &[&str]) -> Value {
for p in paths {
redact_path(&mut value, p);
}
value
}
fn redact_path(doc: &mut Value, pointer: &str) {
if pointer.is_empty() {
*doc = Value::String(REDACTED.to_string());
return;
}
if !pointer.starts_with('/') {
return;
}
let tokens = split_pointer(&pointer[1..]);
redact_tokens(doc, &tokens);
}
fn redact_tokens(node: &mut Value, tokens: &[String]) {
let Some((head, rest)) = tokens.split_first() else {
*node = Value::String(REDACTED.to_string());
return;
};
match node {
Value::Object(map) => {
if let Some(child) = map.get_mut(head) {
redact_tokens(child, rest);
}
}
Value::Array(arr) => {
if let Some(idx) = parse_uint(head) {
if idx < arr.len() {
redact_tokens(&mut arr[idx], rest);
}
}
}
_ => {}
}
}
fn split_pointer(body: &str) -> Vec<String> {
body.split('/')
.map(|p| p.replace("~1", "/").replace("~0", "~"))
.collect()
}
fn parse_uint(s: &str) -> Option<usize> {
if s.is_empty() || !s.bytes().all(|b| b.is_ascii_digit()) {
return None;
}
s.parse().ok()
}