serde_json_merge 0.0.7

Merge, index, iterate, and sort a serde_json::Value (recursively)
use crate::IndexPath;
use crate::iter::{KeyValueIter, Traverser};
use serde_json::Value;
#[cfg(feature = "sort")]
use std::fmt;

pub trait ValueExt {
    fn try_keys(&self) -> Option<Vec<String>>;
}

impl ValueExt for Option<&Value> {
    fn try_keys(&self) -> Option<Vec<String>> {
        self.and_then(|value| match value {
            Value::Object(map) => Some(map.keys().cloned().collect::<Vec<String>>()),
            _ => None,
        })
    }
}

pub trait CollectCloned {
    fn collect_cloned(self) -> Vec<(IndexPath, Value)>;
}

impl<'a, Iter, T> CollectCloned for Iter
where
    Iter: IntoIterator<IntoIter = KeyValueIter<'a, T>>,
    T: Traverser + Clone,
{
    fn collect_cloned(self) -> Vec<(IndexPath, Value)> {
        self.into_iter()
            .map(|(index, value)| (index, value.clone()))
            .collect::<Vec<(IndexPath, Value)>>()
    }
}

#[cfg(feature = "sort")]
#[allow(
    clippy::panic,
    reason = "test assertion helper that is designed to panic on failure"
)]
pub fn assert_failed(
    left: &dyn fmt::Debug,
    op: &str,
    right: &dyn fmt::Debug,
    args: Option<fmt::Arguments<'_>>,
) -> ! {
    match args {
        Some(args) => panic!(
            r"assertion failed: `(left {op} right)`
  left: `{left:?}`,
 right: `{right:?}`: {args:?}"
        ),
        None => panic!(
            r"assertion failed: `(left {op} right)`
  left: `{left:?}`,
 right: `{right:?}`"
        ),
    }
}

#[cfg(feature = "sort")]
macro_rules! assert_eq_ordered {
    ($left:expr, $right:expr $(,)?) => {
        match (&$left, &$right) {
            (left_val, right_val) => {
                if !$crate::sort::PartialEqOrdered::eq(left_val, right_val) {
                    $crate::test::assert_failed(
                        left_val,
                        "equals (ordered)",
                        right_val,
                        std::option::Option::None
                    );
                }
            }
        }
    };
    ($left:expr, $right:expr, $($arg:tt)+) => {
        match (&$left, &$right) {
            (left_val, right_val) => {
                if !$crate::sort::PartialEqOrdered::eq(left_val, right_val) {
                    $crate::test::assert_failed(
                        left_val,
                        "equals (ordered)",
                        right_val,
                        std::option::Option::Some(std::format_args!($($arg)+))
                    );
                }
            }
        }
    };
}

#[cfg(feature = "sort")]
pub(crate) use assert_eq_ordered;

#[cfg(all(feature = "sort", feature = "preserve_order"))]
macro_rules! assert_ne_ordered {
    ($left:expr, $right:expr $(,)?) => {
        match (&$left, &$right) {
            (left_val, right_val) => {
                if $crate::sort::PartialEqOrdered::eq(left_val, right_val) {
                    $crate::test::assert_failed(
                        left_val,
                        "does not equal (ordered)",
                        right_val,
                        std::option::Option::None
                    );
                }
            }
        }
    };
    ($left:expr, $right:expr, $($arg:tt)+) => {
        match (&$left, &$right) {
            (left_val, right_val) => {
                if $crate::sort::PartialEqOrdered::eq(left_val, right_val) {
                    $crate::test::assert_failed(
                        left_val,
                        "does not equal (ordered)",
                        right_val,
                        std::option::Option::Some(std::format_args!($($arg)+))
                    );
                }
            }
        }
    }
}

#[cfg(all(feature = "sort", feature = "preserve_order"))]
pub(crate) use assert_ne_ordered;