use serde_json::{Map, Value};
use crate::Error;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum KeyAction {
Skip,
Walk,
WalkAll,
JsonString,
}
pub trait KeyPolicy: Sync {
fn action(&self, parent: &Map<String, Value>, key: &str) -> KeyAction;
}
pub struct WalkAll;
impl KeyPolicy for WalkAll {
fn action(&self, _: &Map<String, Value>, _: &str) -> KeyAction {
KeyAction::Walk
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum StrKind {
Plain,
Json,
}
pub(crate) type Visitor<'a> = dyn FnMut(&mut String, StrKind) -> Result<(), Error> + 'a;
pub(crate) fn walk(value: &mut Value, policy: &dyn KeyPolicy, f: &mut Visitor<'_>) -> Result<(), Error> {
match value {
Value::String(s) => f(s, StrKind::Plain),
Value::Array(items) => items.iter_mut().try_for_each(|v| walk(v, policy, f)),
Value::Object(map) => {
let actions: Vec<(String, KeyAction)> = map.keys().map(|k| (k.clone(), policy.action(map, k))).collect();
for (key, action) in actions {
let child = map.get_mut(&key).expect("key exists");
match action {
KeyAction::Skip => {}
KeyAction::Walk => walk(child, policy, f)?,
KeyAction::WalkAll => walk(child, &WalkAll, f)?,
KeyAction::JsonString => match child {
Value::String(s) => f(s, StrKind::Json)?,
other => walk(other, &WalkAll, f)?,
},
}
}
Ok(())
}
Value::Null | Value::Bool(_) | Value::Number(_) => Ok(()),
}
}