json-matcher 0.1.0

Utility library for declaratively matching JSON values
Documentation
use std::fmt::Display;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum JsonPathElement {
    Root,
    Index(usize),
    Key(String),
}

impl Display for JsonPathElement {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let s = match self {
            JsonPathElement::Root => "$".to_string(),
            JsonPathElement::Index(index) => format!("{}", index),
            JsonPathElement::Key(key) => key.to_string(),
        };
        write!(f, "{}", s)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct JsonPath(Vec<JsonPathElement>);

impl Display for JsonPath {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            self.0
                .iter()
                .map(|e| format!("{}", e))
                .collect::<Vec<String>>()
                .join(".")
        )
    }
}

impl From<Vec<JsonPathElement>> for JsonPath {
    fn from(elements: Vec<JsonPathElement>) -> Self {
        Self(elements)
    }
}

impl JsonPath {
    pub fn extend<T: Into<JsonPath>>(mut self, elements: T) -> Self {
        let mut elements = Into::<JsonPath>::into(elements).0;
        if elements.first() == Some(&JsonPathElement::Root) {
            elements = elements.into_iter().skip(1).collect();
        }
        let path = &mut self.0;
        path.extend(elements);
        self
    }
}

impl Default for JsonPath {
    fn default() -> Self {
        Self(vec![JsonPathElement::Root])
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct JsonMatcherError {
    pub path: JsonPath,
    pub message: String,
}

impl JsonMatcherError {
    pub fn at_root<T: Into<String>>(message: T) -> Self {
        let message = message.into();
        Self {
            path: JsonPath::default(),
            message,
        }
    }
}

impl Display for JsonMatcherError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}: {}", self.path, self.message)
    }
}