valu3 0.9.6

A generic serialization/deserialization/type framework
Documentation
use crate::prelude::*;
use pest::Parser;
use std::collections::HashMap;

#[derive(Parser)]
#[grammar = "parser/json/json.pest"]
struct JSONParser;

use pest::iterators::Pair;

impl Value {
    pub fn json_to_value(str: &str) -> Result<Value, Error> {
        let value = match JSONParser::parse(Rule::json, str.trim()) {
            Ok(mut pairs) => match pairs.next() {
                Some(pair) => Self::json_parse_value_inner(pair),
                None => return Err(Error::NonParseble),
            },
            Err(msg) => return Err(Error::NonParsebleMsg(msg.to_string())),
        };
        Ok(value)
    }

    fn json_parse_value_inner(pair: Pair<Rule>) -> Self {
        match pair.as_rule() {
            Rule::object => {
                let map = pair
                    .into_inner()
                    .map(|pair| {
                        let mut inner_rules = pair.into_inner();
                        let name = inner_rules
                            .next()
                            .unwrap()
                            .into_inner()
                            .next()
                            .unwrap()
                            .as_str()
                            .to_string();
                        let value = Self::json_parse_value_inner(inner_rules.next().unwrap());
                        (name, value)
                    })
                    .collect::<HashMap<String, Value>>();

                Self::from(map)
            }
            Rule::array => Self::from(
                pair.into_inner()
                    .map(Self::json_parse_value_inner)
                    .collect::<Vec<_>>(),
            ),
            Rule::string => Self::from(StringB::from(pair.into_inner().next().unwrap().as_str())),
            Rule::number => Self::from(Number::try_from(pair.as_str()).unwrap()),
            Rule::boolean => Self::Boolean(pair.as_str().parse().unwrap()),
            Rule::null => Self::Null,
            Rule::json
            | Rule::EOI
            | Rule::key_value_pair
            | Rule::value
            | Rule::inner
            | Rule::char
            | Rule::WHITESPACE => Self::Undefined,
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::prelude::*;
    use std::collections::HashMap;

    #[test]
    fn json() {
        let raw: &str = "{
        \"test\": true,
        \"test2\": \"ok\",
        \"test3\": [0, 1]
       }";

        let compare = Value::from({
            let mut map = HashMap::new();
            map.insert("test".to_string(), true.to_value());
            map.insert("test2".to_string(), "ok".to_value());
            map.insert("test3".to_string(), Value::from(vec![0, 1]));
            map
        });

        assert_eq!(Value::json_to_value(raw), Ok(compare));
    }

    #[test]
    fn array() {
        let raw = "[0, true, null, \"ok\"]";

        let compare = {
            let mut list = Vec::new();
            list.push(Value::Number(Number::from(0)));
            list.push(Value::Boolean(true));
            list.push(Value::Null);
            list.push(Value::String(StringB::from("ok")));
            Value::from(list)
        };

        assert_eq!(Value::json_to_value(raw), Ok(compare));
    }

    #[test]
    fn number() {
        let int = "0";
        let float = "1.0";

        assert_eq!(
            Value::json_to_value(int),
            Ok(Value::Number(Number::from(0)))
        );
        assert_eq!(
            Value::json_to_value(float),
            Ok(Value::Number(Number::from(1.0)))
        );
    }

    #[test]
    fn string() {
        let string = r#""string""#;

        assert_eq!(
            Value::json_to_value(string),
            Ok(Value::String(StringB::from("string")))
        );
    }

    #[test]
    fn null() {
        let null = "null";

        assert_eq!(Value::json_to_value(null), Ok(Value::Null));
    }
    #[test]
    fn boolean() {
        let boolean = "true";

        assert_eq!(Value::json_to_value(boolean), Ok(Value::Boolean(true)));
    }

    #[test]
    fn all() {
        let boolean = Value::json_to_value("true").unwrap();
        let float = Value::json_to_value("3.14").unwrap();
        let json = Value::json_to_value(r#"{"item": 3.14}"#).unwrap();
        let array = Value::json_to_value(r#"[1,2,3]"#).unwrap();
        let null = Value::json_to_value("null").unwrap();
        let string = Value::json_to_value(r#""123""#).unwrap();

        assert_eq!(boolean, true.to_value());
        assert_eq!(float, 3.14.to_value());
        assert_eq!(json, Value::from(vec![("item", 3.14)]));
        assert_eq!(array, vec![1, 2, 3].to_value());
        assert_eq!(null, Value::Null);
        assert_eq!(string, "123".to_value());
    }
}