diff --git a/CHANGELOG-rust.md b/CHANGELOG-rust.md index bd6a316b..a256bcba 100644 --- a/CHANGELOG-rust.md +++ b/CHANGELOG-rust.md @@ -5,6 +5,8 @@ This changelog tracks the Rust `svdtools` project. See ## [Unreleased] +* `convert`: Add `format_config` option + ## [v0.2.4] 2022-05-15 * Added action to build binaries and release for every version tag and latest commit diff --git a/Cargo.toml b/Cargo.toml index 799f2f46..3e26f1b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,9 +27,9 @@ edition = "2021" clap = { version = "3.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] } quick-xml = { version = "0.18", features = ["serialize"] } -svd-rs = { version = "0.13.2", features = ["serde", "derive-from"] } -svd-parser = { version = "0.13.4", features = ["expand"] } -svd-encoder = "0.13.1" +svd-rs = { version = "0.14.0", features = ["serde", "derive-from"] } +svd-parser = { version = "0.14.0", features = ["expand"] } +svd-encoder = "0.14.0" yaml-rust = "0.4" serde_yaml = "0.8.23" serde_json = { version = "1.0", features = ["preserve_order"] } diff --git a/src/cli.rs b/src/cli.rs index f8019c63..6083df6c 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -71,6 +71,14 @@ enum Command { /// Skip enumeratedValues and writeConstraints during parsing (XML input only) #[clap(long)] ignore_enums: bool, + + /// Path to format config file + /// + /// If not specified, the default format config will be used. + /// + /// Only used for SVD output format. + #[clap(long = "format-config", parse(from_os_str))] + format_config: Option, }, } @@ -94,14 +102,18 @@ impl Command { expand, expand_properties, ignore_enums, + format_config, } => convert_cli::convert( in_path, out_path, *input_format, *output_format, - *expand, - *expand_properties, - *ignore_enums, + convert_cli::ParserConfig { + expand: *expand, + expand_properties: *expand_properties, + ignore_enums: *ignore_enums, + }, + format_config.as_ref().map(|p| p.as_path()), )?, } Ok(()) diff --git a/src/convert/convert_cli.rs b/src/convert/convert_cli.rs index b05ad137..b8250091 100644 --- a/src/convert/convert_cli.rs +++ b/src/convert/convert_cli.rs @@ -18,7 +18,7 @@ impl FromStr for InputFormat { "svd" | "SVD" | "xml" | "XML" => Ok(Self::Xml), "yml" | "yaml" | "YAML" => Ok(Self::Yaml), "json" | "JSON" => Ok(Self::Json), - _ => return Err(anyhow!("Unknown input file format")), + _ => Err(anyhow!("Unknown input file format")), } } } @@ -38,19 +38,42 @@ impl FromStr for OutputFormat { "svd" | "SVD" | "xml" | "XML" => Ok(Self::Xml), "yml" | "yaml" | "YAML" => Ok(Self::Yaml), "json" | "JSON" => Ok(Self::Json), - _ => return Err(anyhow!("Unknown output file format")), + _ => Err(anyhow!("Unknown output file format")), } } } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[non_exhaustive] +pub enum ConfigFormat { + Yaml, + Json, +} + +impl FromStr for ConfigFormat { + type Err = anyhow::Error; + fn from_str(s: &str) -> Result { + match s { + "yml" | "yaml" | "YAML" => Ok(Self::Yaml), + "json" | "JSON" => Ok(Self::Json), + _ => Err(anyhow!("Unknown config file format")), + } + } +} + +pub struct ParserConfig { + pub expand: bool, + pub expand_properties: bool, + pub ignore_enums: bool, +} + pub fn convert( in_path: &Path, out_path: &Path, input_format: Option, output_format: Option, - expand: bool, - expand_properties: bool, - ignore_enums: bool, + parser_config: ParserConfig, + format_config: Option<&Path>, ) -> Result<()> { let input_format = match input_format { None => match in_path.extension().and_then(|e| e.to_str()) { @@ -73,22 +96,45 @@ pub fn convert( let mut device = match input_format { InputFormat::Xml => svd_parser::parse_with_config( &input, - &svd_parser::Config::default().ignore_enums(ignore_enums), + &svd_parser::Config::default().ignore_enums(parser_config.ignore_enums), )?, InputFormat::Yaml => serde_yaml::from_str(&input)?, InputFormat::Json => serde_json::from_str(&input)?, }; - if expand_properties { + if parser_config.expand_properties { svd_parser::expand_properties(&mut device); } - let device = if expand { + let device = if parser_config.expand { svd_parser::expand(&device)? } else { device }; + let config = if let Some(format_config) = format_config { + let config_format = match format_config.extension().and_then(|e| e.to_str()) { + Some(s) => ConfigFormat::from_str(s)?, + _ => return Err(anyhow!("Unknown output file format")), + }; + let mut config = String::new(); + File::open(format_config)?.read_to_string(&mut config)?; + + let config_map: std::collections::HashMap = match config_format { + ConfigFormat::Yaml => serde_yaml::from_str(&config)?, + ConfigFormat::Json => serde_json::from_str(&config)?, + }; + + let mut config = svd_encoder::Config::default(); + config_map + .iter() + .for_each(|(name, value)| config.update(name, value)); + + config + } else { + svd_encoder::Config::default() + }; + let output = match output_format { - OutputFormat::Xml => svd_encoder::encode(&device)?, + OutputFormat::Xml => svd_encoder::encode_with_config(&device, &config)?, OutputFormat::Yaml => serde_yaml::to_string(&device)?, OutputFormat::Json => serde_json::to_string_pretty(&device)?, }; diff --git a/src/patch/device.rs b/src/patch/device.rs index d5deee4b..c4f83904 100644 --- a/src/patch/device.rs +++ b/src/patch/device.rs @@ -19,14 +19,9 @@ pub struct PerIter<'a, 'b> { impl<'a, 'b> Iterator for PerIter<'a, 'b> { type Item = &'a mut Peripheral; fn next(&mut self) -> Option { - for next in self.it.by_ref() { - if matchname(&next.name, self.spec) - && !(self.check_derived && next.derived_from.is_some()) - { - return Some(next); - } - } - None + self.it.by_ref().find(|next| { + matchname(&next.name, self.spec) && !(self.check_derived && next.derived_from.is_some()) + }) } } diff --git a/src/patch/iterators.rs b/src/patch/iterators.rs index 833fc369..0acb0146 100644 --- a/src/patch/iterators.rs +++ b/src/patch/iterators.rs @@ -18,12 +18,9 @@ where { type Item = I::Item; fn next(&mut self) -> Option { - for next in self.it.by_ref() { - if matchname(next.name(), self.spec) { - return Some(next); - } - } - None + self.it + .by_ref() + .find(|next| matchname(next.name(), self.spec)) } } @@ -60,7 +57,7 @@ where } } -impl<'a, I> Iterator for OptIter +impl Iterator for OptIter where I: Iterator, {