plugx_config/parser/
yaml.rs

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