serde_json_merge 0.0.7

Merge, index, iterate, and sort a serde_json::Value (recursively)
//! Generic traversal traits and value iterators.

pub mod dfs;
use super::{Index, IndexPath};
use serde_json::Value;

/// Splits a traversal into independent work units for parallel execution.
#[cfg(feature = "rayon")]
pub trait ParallelTraverser: Sized {
    /// Removes and returns a portion of the traversal when one is available.
    fn split(&mut self) -> Option<Self>;
}

/// Controls traversal state for JSON values.
pub trait Traverser {
    /// Creates a traversal with its default depth and limit.
    fn new() -> Self;

    /// Sets the maximum number of visited values, or removes the limit with `None`.
    fn set_limit<L>(&mut self, limit: L)
    where
        L: Into<Option<usize>>;

    /// Sets the maximum traversal depth, or removes the limit with `None`.
    fn set_depth<D>(&mut self, depth: D)
    where
        D: Into<Option<usize>>;

    /// Applies a mutation to the next value and advances the traversal.
    fn mutate_then_next(
        &mut self,
        value: &mut Value,
        mutate: impl FnMut(&IndexPath, &mut Value),
    ) -> Option<IndexPath>;

    /// Returns the next path in the traversal.
    fn next(&mut self, value: &Value) -> Option<IndexPath>;

    /// Processes the next path and reports whether its children should be visited.
    fn process_next(
        &mut self,
        value: &Value,
        process: impl FnMut(&IndexPath, Option<&Value>) -> bool,
    ) -> Option<IndexPath>;

    /// Resets the traversal to its initial state.
    fn reset(&mut self);
}

/// Iterates over paths and values discovered by a [`Traverser`].
#[expect(
    clippy::module_name_repetitions,
    reason = "the type name distinguishes key-value traversal from other iterators"
)]
#[derive(Clone)]
pub struct KeyValueIter<'a, T> {
    inner: &'a Value,
    traverser: T,
}

impl<'a, T> Iterator for KeyValueIter<'a, T>
where
    T: Traverser,
{
    type Item = (IndexPath, &'a Value);

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match self.traverser.next(self.inner).map(|idx| {
                let value = self.inner.get_index(&idx);
                (idx, value)
            }) {
                Some((idx, Some(value))) => return Some((idx, value)),
                None => return None,
                Some(_) => {
                    // continue
                }
            }
        }
    }
}

// #[cfg(feature = "rayon")]
// impl<'a, T> par_dfs::sync::par::SplittableIterator for KeyValueIter<'a, T>
// where
//     T: Traverser + ParallelTraverser,
// {
//     fn split(&mut self) -> Option<Self> {
//         match self.traverser.split() {
//             Some(split) => Some(Self {
//                 traverser: split,
//                 inner: self.inner,
//             }),
//             None => None,
//         }
//     }
// }

// #[cfg(feature = "rayon")]
// impl<'a, T> rayon::iter::IntoParallelIterator for KeyValueIter<'a, T>
// where
//     T: Traverser + ParallelTraverser + Send,
// {
//     type Iter = par_dfs::sync::par::ParallelSplittableIterator<Self>;
//     type Item = <Self as Iterator>::Item;

//     fn into_par_iter(self) -> Self::Iter {
//         par_dfs::sync::par::ParallelSplittableIterator::new(self)
//     }
// }

/// Mutates each path and value discovered by a [`Traverser`].
pub struct KeyValueMutator<'a, T> {
    inner: &'a mut Value,
    traverser: T,
}

impl<T> KeyValueMutator<'_, T>
where
    T: Traverser,
{
    /// Applies a callback to every visited path and value.
    pub fn for_each(&mut self, mut func: impl FnMut(&IndexPath, &mut Value)) {
        self.traverser.reset();
        while self
            .traverser
            .mutate_then_next(self.inner, &mut func)
            .is_some()
        {}
    }
}

/// Provides bounded and recursive traversal methods for JSON values.
pub trait Iter {
    /// Iterates over immediate children using `T`.
    fn iter<T>(&self) -> KeyValueIter<'_, T>
    where
        T: Traverser;

    /// Mutates immediate children using `T`.
    fn mutate<T>(&mut self) -> KeyValueMutator<'_, T>
    where
        T: Traverser;

    /// Iterates recursively through all descendants using `T`.
    fn iter_recursive<T>(&self) -> KeyValueIter<'_, T>
    where
        T: Traverser;

    /// Mutates recursively through all descendants using `T`.
    fn mutate_recursive<T>(&mut self) -> KeyValueMutator<'_, T>
    where
        T: Traverser;
}

impl Iter for Value {
    fn iter<T>(&self) -> KeyValueIter<'_, T>
    where
        T: Traverser,
    {
        let mut traverser = T::new();
        traverser.set_depth(1);
        traverser.set_limit(None);
        KeyValueIter {
            inner: self,
            traverser,
        }
    }

    fn mutate<T>(&mut self) -> KeyValueMutator<'_, T>
    where
        T: Traverser,
    {
        let mut traverser = T::new();
        traverser.set_depth(1);
        traverser.set_limit(None);
        KeyValueMutator {
            inner: self,
            traverser,
        }
    }

    fn iter_recursive<T>(&self) -> KeyValueIter<'_, T>
    where
        T: Traverser,
    {
        let mut traverser = T::new();
        traverser.set_depth(None);
        traverser.set_limit(None);
        KeyValueIter {
            inner: self,
            traverser,
        }
    }

    fn mutate_recursive<T>(&mut self) -> KeyValueMutator<'_, T>
    where
        T: Traverser,
    {
        let mut traverser = T::new();
        traverser.set_depth(None);
        traverser.set_limit(None);
        KeyValueMutator {
            inner: self,
            traverser,
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::index;
    use crate::iter::dfs::Dfs;
    use crate::test::CollectCloned;
    use pretty_assertions::assert_eq;
    use serde_json::json;

    #[test]
    fn nonterminal_value_iter() {
        let value = json!({
            "person1": { "name": "bob" },
            "person2": { "name": "john" },
        });
        assert_eq!(
            value.iter::<Dfs>().collect_cloned(),
            vec![
                //  todo: depth 0 should be skipped
                (index!(), value.clone()),
                (index!("person1"), json!({ "name": "bob" })),
                (index!("person2"), json!({ "name": "john" })),
            ]
        );
        // todo: same as bfs
        assert_eq!(
            value.iter::<Dfs>().collect_cloned(),
            value.iter::<Dfs>().collect_cloned()
        );
    }

    #[test]
    fn value_iter_recursive_dfs() {
        let value = json!({
            "person1": { "name": "bob" },
            "person2": { "name": "john" },
        });
        assert_eq!(
            value.iter_recursive::<Dfs>().collect_cloned(),
            vec![
                (index!(), value),
                (index!("person1"), json!({ "name": "bob" })),
                (index!("person1", "name"), json!("bob")),
                (index!("person2"), json!({ "name": "john" })),
                (index!("person2", "name"), json!("john")),
            ]
        );
    }
}