json-grep 0.1.0

A grep-like utility for searching JSON data with regular expressions
Documentation
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))
    }
}