plugx_config/parser/
json.rs

1//! JSON configuration parser.
2//!
3//! This is only usable if you enabled `json` Cargo feature.
4//!
5//! ### Example
6//! ```rust
7//! use plugx_config::parser::{Parser, json::Json};
8//! use plugx_input::Input;
9//!
10//! let bytes = br#"
11//! {
12//!     "hello": ["w", "o", "l", "d"],
13//!     "foo": {
14//!         "bar": {
15//!             "baz": "Qux",
16//!             "abc": 3.14
17//!         },
18//!         "xyz": false
19//!     }
20//! }
21//! "#;
22//!
23//! let parser = Json::new();
24//! let parsed: Input = parser.parse(bytes.as_slice()).unwrap();
25//!
26//! assert!(parsed.is_map());
27//! let map = parsed.as_map();
28//! assert!(
29//!     map.len() == 2 &&
30//!     map.contains_key("foo") &&
31//!     map.contains_key("hello")
32//! );
33//! ```
34
35use crate::parser::Parser;
36use anyhow::anyhow;
37use cfg_if::cfg_if;
38use plugx_input::Input;
39use std::fmt::{Debug, Display, Formatter};
40
41#[derive(Clone, Copy, Default)]
42pub struct Json;
43
44impl Display for Json {
45    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
46        f.write_str("JSON")
47    }
48}
49
50impl Debug for Json {
51    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
52        f.debug_struct("ConfigurationParserJson").finish()
53    }
54}
55
56impl Json {
57    pub fn new() -> Self {
58        Default::default()
59    }
60}
61
62impl Parser for Json {
63    fn supported_format_list(&self) -> Vec<String> {
64        ["json".into()].into()
65    }
66
67    fn try_parse(&self, bytes: &[u8]) -> anyhow::Result<Input> {
68        serde_json::from_slice(bytes)
69            .map(|parsed: Input| {
70                cfg_if! {
71                    if #[cfg(feature = "tracing")] {
72                        tracing::trace!(
73                            input=String::from_utf8_lossy(bytes).to_string(),
74                            output=%parsed,
75                            "Parsed JSON contents"
76                        );
77                    } else if #[cfg(feature = "logging")] {
78                        log::trace!(
79                            "msg=\"Parsed JSON contents\" input={:?} output={:?}",
80                            String::from_utf8_lossy(bytes).to_string(),
81                            parsed.to_string()
82                        );
83                    }
84                }
85                parsed
86            })
87            .map_err(|error| anyhow!(error))
88    }
89
90    fn is_format_supported(&self, bytes: &[u8]) -> Option<bool> {
91        Some(serde_json::from_slice::<serde_json::Value>(bytes).is_ok())
92    }
93}