headj 0.1.1

A utility that converts input JSON arrays into valid JSON that contains only a subset of the elements
Documentation
use eyre::Result;
use json_event_parser::JsonEvent;
use std::iter::Iterator;
use std::ops::Index;

#[derive(Clone, Debug, PartialEq)]
pub enum OwnedJsonEvent {
    String(String),
    Number(String),
    Boolean(bool),
    Null,
    StartArray,
    EndArray,
    StartObject,
    EndObject,
    ObjectKey(String),
    Eof,
}

impl OwnedJsonEvent {
    pub fn as_json_event(&self) -> JsonEvent {
        match self {
            Self::String(s) => JsonEvent::String(s),
            Self::Number(s) => JsonEvent::Number(s),
            Self::ObjectKey(s) => JsonEvent::ObjectKey(s),
            Self::Boolean(b) => JsonEvent::Boolean(*b),
            Self::Null => JsonEvent::Null,
            Self::StartArray => JsonEvent::StartArray,
            Self::EndArray => JsonEvent::EndArray,
            Self::StartObject => JsonEvent::StartObject,
            Self::EndObject => JsonEvent::EndObject,
            Self::Eof => JsonEvent::Eof,
        }
    }
}

#[derive(Default)]
pub struct KeyPath {
    json_path: Vec<OwnedJsonEvent>,
}

#[allow(clippy::len_without_is_empty)]
impl KeyPath {
    pub fn from_kp_str(key_path_str: &str) -> Result<Self> {
        let mut json_path = Vec::new();
        let mut quote = false;
        let mut current_key = String::new();
        for c in key_path_str.chars() {
            if quote {
                current_key.push(c);
                quote = false;
            } else {
                match c {
                    // TODO: add brackets
                    '\\' => quote = true,
                    '.' => {
                        let element = OwnedJsonEvent::ObjectKey(std::mem::take(&mut current_key));
                        json_path.push(element);
                        current_key = String::new();
                    }
                    _ => current_key.push(c),
                }
            };
        }
        if !current_key.is_empty() {
            let element = OwnedJsonEvent::ObjectKey(std::mem::take(&mut current_key));
            json_path.push(element);
        }
        Ok(Self { json_path })
    }

    pub fn iterator(&self) -> impl Iterator<Item = &OwnedJsonEvent> + '_ {
        self.json_path.iter()
    }

    pub fn len(&self) -> usize {
        self.json_path.len()
    }
}

impl Index<usize> for KeyPath {
    type Output = OwnedJsonEvent;
    fn index(&self, idx: usize) -> &Self::Output {
        &self.json_path[idx]
    }
}

#[cfg(test)]
mod tests {
    use crate::key_path::OwnedJsonEvent::ObjectKey;
    use crate::key_path::{KeyPath, OwnedJsonEvent};
    use json_event_parser::JsonEvent;

    #[test]
    fn test_owned_json_event() {
        let e = OwnedJsonEvent::ObjectKey(String::from("key"));
        assert_eq!(e.as_json_event(), JsonEvent::ObjectKey("key"));
        let e = OwnedJsonEvent::String(String::from("string"));
        assert_eq!(e.as_json_event(), JsonEvent::String("string"));
        let e = OwnedJsonEvent::Number(String::from("27"));
        assert_eq!(e.as_json_event(), JsonEvent::Number("27"));
        let e = OwnedJsonEvent::Boolean(true);
        assert_eq!(e.as_json_event(), JsonEvent::Boolean(true));
        assert_eq!(OwnedJsonEvent::Null.as_json_event(), JsonEvent::Null);
        assert_eq!(OwnedJsonEvent::Eof.as_json_event(), JsonEvent::Eof);
        assert_eq!(
            OwnedJsonEvent::StartArray.as_json_event(),
            JsonEvent::StartArray
        );
        assert_eq!(
            OwnedJsonEvent::EndArray.as_json_event(),
            JsonEvent::EndArray
        );
        assert_eq!(
            OwnedJsonEvent::StartObject.as_json_event(),
            JsonEvent::StartObject
        );
        assert_eq!(
            OwnedJsonEvent::EndObject.as_json_event(),
            JsonEvent::EndObject
        );
    }

    #[test]
    fn test_blank_key_path() {
        let key_path = KeyPath::from_kp_str("").unwrap();
        assert_eq!(0, key_path.len())
    }

    #[test]
    fn test_one_element_with_backslash_dot() {
        let key_path = KeyPath::from_kp_str("foo\\.bar").unwrap();
        assert_eq!(1, key_path.len());
        let event_0 = OwnedJsonEvent::ObjectKey("foo.bar".to_string());
        assert_eq!(event_0, key_path[0]);
    }

    #[test]
    fn test_one_element() {
        let key_path = KeyPath::from_kp_str("foo").unwrap();
        assert_eq!(1, key_path.len());
        let event_0 = OwnedJsonEvent::ObjectKey("foo".to_string());
        assert_eq!(event_0, key_path[0]);
    }

    #[test]
    fn test_three_elements_with_backslash() {
        let key_path = KeyPath::from_kp_str("foo.bar\\\\.baz").unwrap();
        assert_eq!(3, key_path.len());
        let events = [
            ObjectKey("foo".to_string()),
            ObjectKey("bar\\".to_string()),
            ObjectKey("baz".to_string()),
        ];
        for index in 0..2 {
            assert_eq!(events[index], key_path[index]);
        }
    }

    #[test]
    fn test_three_elements() {
        let key_path = KeyPath::from_kp_str("foo.bar.baz").unwrap();
        assert_eq!(3, key_path.len());
        let events = [
            ObjectKey("foo".to_string()),
            ObjectKey("bar".to_string()),
            ObjectKey("baz".to_string()),
        ];
        for index in 0..2 {
            assert_eq!(events[index], key_path[index]);
        }
    }
}