use std::borrow::Cow;
use std::fmt::{self, Write as _};
use regex::RegexSet;
use serde::de;
pub trait Callback<'a> {
fn on_match(&mut self, matched: &str) -> bool;
fn on_finish(&mut self) -> bool {
false
}
fn push_index(&mut self) {}
fn bump_index(&mut self) {}
fn pop_index(&mut self) {}
fn push_key(&mut self) {}
fn set_key(&mut self, _key: Cow<'a, str>) {}
fn pop_key(&mut self) {}
}
impl<'a, C1: Callback<'a>, C2: Callback<'a>> Callback<'a> for (C1, C2) {
fn on_match(&mut self, matched: &str) -> bool {
self.0.on_match(matched) || self.1.on_match(matched)
}
fn on_finish(&mut self) -> bool {
self.0.on_finish() || self.1.on_finish()
}
fn push_index(&mut self) {
self.0.push_index();
self.1.push_index();
}
fn bump_index(&mut self) {
self.0.bump_index();
self.1.bump_index();
}
fn pop_index(&mut self) {
self.0.pop_index();
self.1.pop_index();
}
fn push_key(&mut self) {
self.0.push_key();
self.1.push_key();
}
fn set_key(&mut self, key: Cow<'a, str>) {
self.0.set_key(key.clone());
self.1.set_key(key);
}
fn pop_key(&mut self) {
self.0.pop_key();
self.1.pop_key();
}
}
pub trait PathCallback<'a> {
fn path(&mut self) -> &mut Path<'a>;
fn on_match(&mut self, matched: &str) -> bool;
fn on_finish(&mut self) -> bool {
false
}
}
impl<'a, C: PathCallback<'a>> Callback<'a> for C {
fn on_match(&mut self, matched: &str) -> bool {
PathCallback::on_match(self, matched)
}
fn on_finish(&mut self) -> bool {
PathCallback::on_finish(self)
}
fn push_index(&mut self) {
self.path().push_index();
}
fn bump_index(&mut self) {
self.path().bump_index();
}
fn pop_index(&mut self) {
self.path().pop();
}
fn push_key(&mut self) {
self.path().push_key();
}
fn set_key(&mut self, key: Cow<'a, str>) {
self.path().set_key(key);
}
fn pop_key(&mut self) {
self.path().pop();
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Path<'a>(Vec<PathSegment<'a>>);
impl<'a> Path<'a> {
fn push_index(&mut self) {
self.0.push(PathSegment::Index(0));
}
fn bump_index(&mut self) {
match self.0.last_mut() {
Some(PathSegment::Index(index)) => *index += 1,
_ => unreachable!(),
}
}
fn push_key(&mut self) {
self.0.push(PathSegment::Key(Cow::Borrowed("")));
}
fn set_key(&mut self, value: Cow<'a, str>) {
match self.0.last_mut() {
Some(PathSegment::Key(key)) => *key = value,
_ => unreachable!(),
}
}
fn pop(&mut self) {
self.0.pop();
}
}
impl fmt::Display for Path<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char('$')?;
self.0.iter().try_for_each(|segment| write!(f, "{segment}"))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PathSegment<'a> {
Index(usize),
Key(Cow<'a, str>),
}
impl fmt::Display for PathSegment<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Index(index) => write!(f, "[{index}]"),
Self::Key(key) => write!(f, "['{}']", JsonPathNormalisedName(key)),
}
}
}
struct JsonPathNormalisedName<'a>(&'a str);
impl fmt::Display for JsonPathNormalisedName<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for c in self.0.chars() {
match c {
'\\' => f.write_str("\\\\")?,
'\'' => f.write_str("\\'")?,
'\x08' => f.write_str("\\b")?,
'\t' => f.write_str("\\t")?,
'\n' => f.write_str("\\n")?,
'\x0C' => f.write_str("\\f")?,
'\r' => f.write_str("\\r")?,
'\0'..' ' => write!(f, "\\u{:04x}", c as u32)?,
_ => f.write_char(c)?,
}
}
Ok(())
}
}
pub struct Walker<'b, C: ?Sized> {
patterns: RegexSet,
invert: bool,
callback: &'b mut C,
}
impl<'a, 'b, C: Callback<'a> + ?Sized> Walker<'b, C> {
pub fn new(patterns: RegexSet, invert: bool, callback: &'b mut C) -> Self {
Self {
patterns,
invert,
callback,
}
}
fn seq_loop<'de: 'a, A: de::SeqAccess<'de>>(&mut self, mut seq: A) -> Result<bool, A::Error> {
while let Some(stop) = seq.next_element_seed(&mut *self)? {
if stop {
return Self::drain_seq(seq);
}
self.callback.bump_index();
}
Ok(false)
}
fn map_loop<'de: 'a, A: de::MapAccess<'de>>(&mut self, mut map: A) -> Result<bool, A::Error> {
while let Some(key) = map.next_key_seed(MapKeyVisitor)? {
self.callback.set_key(key);
if map.next_value_seed(&mut *self)? {
return Self::drain_map(map);
}
}
Ok(false)
}
fn drain_seq<'de: 'a, A: de::SeqAccess<'de>>(mut seq: A) -> Result<bool, A::Error> {
while let Some(de::IgnoredAny) = seq.next_element()? {}
Ok(true)
}
fn drain_map<'de: 'a, A: de::MapAccess<'de>>(mut map: A) -> Result<bool, A::Error> {
while let Some((de::IgnoredAny, de::IgnoredAny)) = map.next_entry()? {}
Ok(true)
}
}
impl<'de: 'a, 'a, C: Callback<'a> + ?Sized> de::DeserializeSeed<'de> for &mut Walker<'_, C> {
type Value = bool;
fn deserialize<D: de::Deserializer<'de>>(
self,
deserializer: D,
) -> Result<Self::Value, D::Error> {
deserializer.deserialize_any(self)
}
}
impl<'de: 'a, 'a, C: Callback<'a> + ?Sized> de::Visitor<'de> for &mut Walker<'_, C> {
type Value = bool;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a JSON value")
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(false)
}
fn visit_bool<E: de::Error>(self, _v: bool) -> Result<Self::Value, E> {
Ok(false)
}
fn visit_u64<E: de::Error>(self, _v: u64) -> Result<Self::Value, E> {
Ok(false)
}
fn visit_i64<E: de::Error>(self, _v: i64) -> Result<Self::Value, E> {
Ok(false)
}
fn visit_f64<E: de::Error>(self, _v: f64) -> Result<Self::Value, E> {
Ok(false)
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
Ok(self.patterns.is_match(v) != self.invert && self.callback.on_match(v))
}
fn visit_seq<A: de::SeqAccess<'de>>(self, seq: A) -> Result<Self::Value, A::Error> {
self.callback.push_index();
let result = self.seq_loop(seq);
self.callback.pop_index();
result
}
fn visit_map<A: de::MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
self.callback.push_key();
let result = self.map_loop(map);
self.callback.pop_key();
result
}
}
struct MapKeyVisitor;
impl<'de> de::DeserializeSeed<'de> for MapKeyVisitor {
type Value = Cow<'de, str>;
fn deserialize<D: de::Deserializer<'de>>(
self,
deserializer: D,
) -> Result<Self::Value, D::Error> {
deserializer.deserialize_str(self)
}
}
impl<'de> de::Visitor<'de> for MapKeyVisitor {
type Value = Cow<'de, str>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a string")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
Ok(Cow::Owned(v.to_owned()))
}
fn visit_borrowed_str<E: de::Error>(self, v: &'de str) -> Result<Self::Value, E> {
Ok(Cow::Borrowed(v))
}
fn visit_string<E: de::Error>(self, v: String) -> Result<Self::Value, E> {
Ok(Cow::Owned(v))
}
}