jsona 0.6.0

A JSONA parser, analyzer and formatter library
Documentation
use super::{DomNode, Keys, Node};

type VisitFn<'a, T> = Box<dyn Fn(&Keys, &Node, &T) -> VisitControl + 'a>;

pub struct Visitor<'a, T> {
    node: &'a Node,
    state: &'a T,
    f: VisitFn<'a, T>,
}

impl<'a, T> Visitor<'a, T> {
    pub fn new(
        node: &'a Node,
        state: &'a T,
        f: impl Fn(&Keys, &Node, &T) -> VisitControl + 'a,
    ) -> Self {
        Self {
            node,
            state,
            f: Box::new(f),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VisitControl {
    AddIter,
    NotAddIter,
    AddNotIter,
    NotAddNotIter,
}

impl<'a, T> IntoIterator for Visitor<'a, T> {
    type Item = (Keys, Node);
    type IntoIter = std::vec::IntoIter<(Keys, Node)>;

    fn into_iter(self) -> Self::IntoIter {
        let mut all = vec![];
        collect(Keys::default(), self.node, self.state, &mut all, &self.f);
        all.into_iter()
    }
}

fn collect<T>(
    keys: Keys,
    node: &Node,
    state: &T,
    all: &mut Vec<(Keys, Node)>,
    f: &dyn Fn(&Keys, &Node, &T) -> VisitControl,
) {
    match f(&keys, node, state) {
        VisitControl::AddIter => {
            all.push((keys.clone(), node.clone()));
        }
        VisitControl::NotAddIter => {}
        VisitControl::AddNotIter => {
            all.push((keys.clone(), node.clone()));
            return;
        }
        VisitControl::NotAddNotIter => {
            return;
        }
    }
    match node {
        Node::Object(obj) => {
            let props = obj.inner.properties.read();
            for (key, node) in props.iter() {
                collect(keys.join(key.clone()), node, state, all, &f);
            }
        }
        Node::Array(arr) => {
            let items = arr.inner.items.read();
            for (idx, node) in items.iter().enumerate() {
                collect(keys.join(idx), node, state, all, &f);
            }
        }
        _ => {}
    }

    if let Some(annotations) = node.annotations() {
        let map = annotations.value().read();
        for (key, node) in map.iter() {
            collect(keys.join(key.clone()), node, state, all, &f);
        }
    }
}

pub fn visit_annotations(node: &Node) -> Visitor<()> {
    Visitor::new(node, &(), |keys, _, _| {
        if keys
            .last()
            .map(|v| v.is_annotation_key())
            .unwrap_or_default()
        {
            VisitControl::AddNotIter
        } else {
            VisitControl::NotAddIter
        }
    })
}