diff --git a/ligen/common/src/lib.rs b/ligen/common/src/lib.rs index 5ca09992..bae9c9cc 100644 --- a/ligen/common/src/lib.rs +++ b/ligen/common/src/lib.rs @@ -1,6 +1,7 @@ pub mod error; pub use error::*; +pub use serde; pub use serde::{Serialize, Deserialize}; pub use derive_more::Display; pub use std::convert::{TryFrom, TryInto}; diff --git a/ligen/ir/src/literal/mod.rs b/ligen/ir/src/literal/mod.rs index b95e339a..0842ee7b 100644 --- a/ligen/ir/src/literal/mod.rs +++ b/ligen/ir/src/literal/mod.rs @@ -6,6 +6,7 @@ pub mod mock; /// Literal Enum #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, EnumAsInner)] +#[serde(untagged)] pub enum Literal { /// String variant String(String), diff --git a/ligen/ir/src/path/mod.rs b/ligen/ir/src/path/mod.rs index 88dee5aa..51cea6a9 100644 --- a/ligen/ir/src/path/mod.rs +++ b/ligen/ir/src/path/mod.rs @@ -17,6 +17,11 @@ pub struct Path { } impl Path { + /// Is empty. + pub fn is_empty(&self) -> bool { + self.segments.is_empty() + } + /// Get `Path` from a `string` with a specified `separator`. pub fn from_string_with_separator(string: &str, separator: impl AsRef) -> Self { let separator = separator.as_ref(); diff --git a/ligen/parsing/Cargo.toml b/ligen/parsing/Cargo.toml index e31b1179..1eb8a12a 100644 --- a/ligen/parsing/Cargo.toml +++ b/ligen/parsing/Cargo.toml @@ -13,6 +13,8 @@ ligen-ir.workspace = true ligen-common.workspace = true pretty_assertions.workspace = true syn.workspace = true +toml = "0.8.6" +serde.workspace = true [dev-dependencies] ligen-ir = { workspace = true, features = ["mocks"] } \ No newline at end of file diff --git a/ligen/parsing/src/parser/config.rs b/ligen/parsing/src/parser/config.rs index 455332ab..006a12db 100644 --- a/ligen/parsing/src/parser/config.rs +++ b/ligen/parsing/src/parser/config.rs @@ -1,43 +1,82 @@ + +use crate::prelude::*; + use std::collections::HashMap; -use ligen_ir::Literal; +use ligen_ir::{Literal, Path}; -#[derive(Default)] +#[derive(Default, Serialize, Deserialize)] pub struct ParserConfig { - map: HashMap + #[serde(flatten)] + map: Group } -impl ParserConfig { - pub fn get(&self, key: &str) -> Option<&Literal> { - self.map.get(key) - } +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +enum Value { + Literal(Literal), + Group(Group) } -impl, L: Into, I: IntoIterator> From for ParserConfig -{ - fn from(input: I) -> Self { - let mut map = HashMap::new(); - for (key, value) in input.into_iter() { - map.insert(key.into(), value.into()); +#[derive(Default, Serialize, Deserialize)] +struct Group { + #[serde(flatten)] + map: HashMap +} + +impl Group { + fn get>(&self, path: P) -> Option<&Literal> { + let mut path = path.into(); + if let Some(word) = path.pop_front() { + match self + .map + .get(&word.identifier.name) { + Some(Value::Literal(literal)) => { + if path.is_empty() { + Some(literal) + } else { + None + } + }, + Some(Value::Group(group)) => group.get(path), + None => None + } + } else { + None } - Self { map } + } +} + +impl TryFrom<&str> for ParserConfig { + type Error = toml::de::Error; + fn try_from(value: &str) -> std::result::Result { + toml::from_str(value) + } +} + +impl ParserConfig { + pub fn get>(&self, path: P) -> Option<&Literal> { + self.map.get(path) } } #[cfg(test)] mod tests { - use ligen_ir::Literal; - use super::ParserConfig; + fn config() -> ParserConfig { + ParserConfig::try_from(r#" + [ligen] + parse-all = false + default-name = "library""# + ).unwrap() + } + #[test] fn parser_config() { - let config = ParserConfig::from([ - ("parser::config::string", Literal::from("test")), - ("parser::config::bool", Literal::from(true)) - ]); - assert_eq!(config.get("parser::config::none"), None); - assert_eq!(config.get("parser::config::string"), Some(&"test".into())); - assert_eq!(config.get("parser::config::bool"), Some(&true.into())); + let config = config(); + assert_eq!(config.get("ligen::parse_all"), None); + assert_eq!(config.get("ligen::parse-all"), Some(&false.into())); + assert_eq!(config.get("ligen::default-name"), Some(&"library".into())); } } \ No newline at end of file