gray_matter/engine/
json.rs

1use crate::engine::Engine;
2use crate::Pod;
3use crate::{Error, Result};
4use json::Value;
5use std::collections::HashMap;
6
7/// [`Engine`](crate::engine::Engine) for the [JSON](https://www.json.org/) configuration format.
8pub struct JSON;
9
10impl Engine for JSON {
11    fn parse(content: &str) -> Result<Pod> {
12        match content.parse::<Value>() {
13            Ok(data) => Ok(data.into()),
14            Err(e) => Err(Error::deserialize_error(&format!("{}", e))),
15        }
16    }
17}
18
19impl From<Value> for Pod {
20    fn from(json_val: Value) -> Self {
21        match json_val {
22            Value::Null => Pod::Null,
23            Value::String(val) => Pod::String(val),
24            Value::Number(val) => {
25                if let Some(int) = val.as_i64() {
26                    Pod::Integer(int)
27                } else {
28                    // NOTE: Looking at the source of serde_json, it looks like `as_f64` will
29                    // always be Some. https://docs.rs/serde_json/latest/src/serde_json/number.rs.html#240-249
30                    Pod::Float(val.as_f64().unwrap())
31                }
32            }
33            Value::Bool(val) => Pod::Boolean(val),
34            Value::Array(val) => val
35                .iter()
36                .map(|elem| elem.into())
37                .collect::<Vec<Pod>>()
38                .into(),
39            Value::Object(val) => val
40                .iter()
41                .map(|(key, elem)| (key.to_owned(), elem.into()))
42                .collect::<HashMap<String, Pod>>()
43                .into(),
44        }
45    }
46}
47
48impl From<&Value> for Pod {
49    fn from(val: &Value) -> Self {
50        val.to_owned().into()
51    }
52}
53
54#[cfg(test)]
55mod test {
56    use crate::engine::JSON;
57    use crate::Matter;
58    use crate::ParsedEntity;
59    use crate::Result;
60    use serde::Deserialize;
61
62    #[test]
63    fn test_matter() -> Result<()> {
64        let matter: Matter<JSON> = Matter::new();
65        let input = r#"---
66{
67    "title": "JSON",
68     "description": "Front Matter"
69}
70---
71Some excerpt
72---
73Other stuff"#;
74        #[derive(PartialEq, Deserialize, Debug)]
75        struct FrontMatter {
76            title: String,
77            description: String,
78        }
79        let data_expected = FrontMatter {
80            title: "JSON".to_string(),
81            description: "Front Matter".to_string(),
82        };
83        let result: ParsedEntity<FrontMatter> = matter.parse(input)?;
84        assert_eq!(result.data, Some(data_expected));
85        Ok(())
86    }
87}