plugx_config/parser/
toml.rs

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