From 604581bb0e57dc36c80e3b23d37c8725a9254254 Mon Sep 17 00:00:00 2001 From: Mathias Brossard Date: Sat, 22 Feb 2025 15:21:16 -0600 Subject: [PATCH 1/2] Run cargo clippy and fmt --- rust/.clippy.toml | 2 + rust/cmsis-cffi/src/config.rs | 7 +- rust/cmsis-cli/src/config.rs | 1 + rust/cmsis-cli/src/lib.rs | 32 +++---- rust/cmsis-pack/src/lib.rs | 2 + rust/cmsis-pack/src/pdsc/device.rs | 45 +++++---- rust/cmsis-pack/src/pdsc/mod.rs | 6 +- rust/cmsis-pack/src/update/download.rs | 125 ++++++++++++------------- rust/cmsis-pack/src/update/mod.rs | 2 +- rust/cmsis-pack/src/utils/parse.rs | 23 ++--- 10 files changed, 118 insertions(+), 127 deletions(-) create mode 100644 rust/.clippy.toml diff --git a/rust/.clippy.toml b/rust/.clippy.toml new file mode 100644 index 000000000..75019f3ac --- /dev/null +++ b/rust/.clippy.toml @@ -0,0 +1,2 @@ +avoid-breaking-exported-api = true +msrv = "1.71.0" diff --git a/rust/cmsis-cffi/src/config.rs b/rust/cmsis-cffi/src/config.rs index c85c8f347..bd38aa056 100644 --- a/rust/cmsis-cffi/src/config.rs +++ b/rust/cmsis-cffi/src/config.rs @@ -12,6 +12,7 @@ pub struct Config { pack_store: PathBuf, } +#[derive(Default)] pub struct ConfigBuilder { pack_store: Option, } @@ -40,12 +41,6 @@ impl ConfigBuilder { } } -impl Default for ConfigBuilder { - fn default() -> Self { - Self { pack_store: None } - } -} - impl Config { pub fn new() -> Result { ConfigBuilder::default().build() diff --git a/rust/cmsis-cli/src/config.rs b/rust/cmsis-cli/src/config.rs index c6a67b200..9b219ab89 100644 --- a/rust/cmsis-cli/src/config.rs +++ b/rust/cmsis-cli/src/config.rs @@ -68,6 +68,7 @@ impl Config { } match OpenOptions::new() .create(true) + .truncate(true) .write(true) .open(&self.vidx_list) { diff --git a/rust/cmsis-cli/src/lib.rs b/rust/cmsis-cli/src/lib.rs index 507835422..f7ce7a260 100644 --- a/rust/cmsis-cli/src/lib.rs +++ b/rust/cmsis-cli/src/lib.rs @@ -62,7 +62,7 @@ pub fn install_args() -> App<'static, 'static> { ) } -pub fn install_command<'a>(conf: &Config, args: &ArgMatches<'a>) -> Result<(), Error> { +pub fn install_command(conf: &Config, args: &ArgMatches<'_>) -> Result<(), Error> { let pdsc_list: Vec<_> = args .values_of("PDSC") .unwrap() @@ -91,7 +91,7 @@ pub fn update_args<'a, 'b>() -> App<'a, 'b> { .version("0.1.0") } -pub fn update_command<'a>(conf: &Config, _: &ArgMatches<'a>) -> Result<(), Error> { +pub fn update_command(conf: &Config, _: &ArgMatches<'_>) -> Result<(), Error> { let vidx_list = conf.read_vidx_list(); for url in vidx_list.iter() { log::info!("Updating registry from `{}`", url); @@ -136,7 +136,7 @@ pub fn dump_devices_args<'a, 'b>() -> App<'a, 'b> { ) } -pub fn dump_devices_command<'a>(c: &Config, args: &ArgMatches<'a>) -> Result<(), Error> { +pub fn dump_devices_command(c: &Config, args: &ArgMatches<'_>) -> Result<(), Error> { let files = args .value_of("INPUT") .map(|input| vec![Path::new(input).to_path_buf()]); @@ -175,27 +175,27 @@ pub fn check_args<'a, 'b>() -> App<'a, 'b> { ) } -pub fn check_command<'a>(_: &Config, args: &ArgMatches<'a>) -> Result<(), Error> { +pub fn check_command(_: &Config, args: &ArgMatches<'_>) -> Result<(), Error> { let filename = args.value_of("INPUT").unwrap(); match Package::from_path(Path::new(filename)) { Ok(c) => { log::info!("Parsing succedded"); - log::info!("{} Valid Conditions", c.conditions.0.iter().count()); + log::info!("{} Valid Conditions", c.conditions.0.len()); let cond_lookup = c.make_condition_lookup(); let mut num_components = 0; let mut num_files = 0; - for &Component { - ref class, - ref group, - ref condition, - ref files, + for Component { + class, + group, + condition, + files, .. } in c.make_components().iter() { num_components += 1; - num_files += files.iter().count(); + num_files += files.len(); if let Some(ref cond_name) = condition { - if cond_lookup.get(cond_name.as_str()).is_none() { + if !cond_lookup.contains_key(cond_name.as_str()) { log::warn!( "Component {}::{} references an unknown condition '{}'", class, @@ -204,14 +204,12 @@ pub fn check_command<'a>(_: &Config, args: &ArgMatches<'a>) -> Result<(), Error> ); } } - for &FileRef { - ref path, - ref condition, - .. + for FileRef { + path, condition, .. } in files.iter() { if let Some(ref cond_name) = condition { - if cond_lookup.get(cond_name.as_str()).is_none() { + if !cond_lookup.contains_key(cond_name.as_str()) { log::warn!( "File {:?} Component {}::{} references an unknown condition '{}'", path, diff --git a/rust/cmsis-pack/src/lib.rs b/rust/cmsis-pack/src/lib.rs index acc777b42..a3c842975 100644 --- a/rust/cmsis-pack/src/lib.rs +++ b/rust/cmsis-pack/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(clippy::upper_case_acronyms)] + pub mod pack_index; pub mod pdsc; pub mod update; diff --git a/rust/cmsis-pack/src/pdsc/device.rs b/rust/cmsis-pack/src/pdsc/device.rs index 81dff3c9c..03c088744 100644 --- a/rust/cmsis-pack/src/pdsc/device.rs +++ b/rust/cmsis-pack/src/pdsc/device.rs @@ -162,11 +162,13 @@ impl ProcessorBuilder { mpu: self.mpu.or(other.mpu.clone()), } } - fn build(self, debugs: &Vec) -> Result, Error> { + fn build(self, debugs: &[Debug]) -> Result, Error> { let units = self.units.unwrap_or(1); let name = self.name.clone(); - let map = (0..units) + + + (0..units) .map(|unit| { // The attributes we're interested in may be spread across multiple debug // attributes defined in the family, subfamily, or device; and which may or may not @@ -176,7 +178,10 @@ impl ProcessorBuilder { // family and subfamily debug elements are appended after device debug elements. let debugs_iterator = debugs.iter().filter(|debug| { // If Pname or Punit are present on the element, they must match. - debug.name.as_ref().map_or(true, |n| Some(n) == name.as_ref()) + debug + .name + .as_ref() + .map_or(true, |n| Some(n) == name.as_ref()) && debug.unit.map_or(true, |u| u == unit) }); @@ -204,9 +209,7 @@ impl ProcessorBuilder { .find_map(|d| d.default_reset_sequence.clone()), }) }) - .collect::, _>>(); - - map + .collect::, _>>() } } @@ -240,7 +243,7 @@ impl ProcessorsBuilder { } fn merge_into(&mut self, other: Self) { - self.0.extend(other.0.into_iter()); + self.0.extend(other.0); } fn build(self, debugs: Vec) -> Result, Error> { @@ -362,12 +365,12 @@ impl DebugsBuilder { impl DebugsBuilder { fn merge(mut self, parent: &Self) -> Self { - self.0.extend(parent.0.iter().map(|v| v.clone())); + self.0.extend(parent.0.iter().cloned()); self } fn merge_into(&mut self, other: Self) { - self.0.extend(other.0.into_iter()) + self.0.extend(other.0) } fn build(self) -> Vec { @@ -418,9 +421,9 @@ enum NumberBool { True, } -impl Into for NumberBool { - fn into(self) -> bool { - match self { +impl From for bool { + fn from(val: NumberBool) -> Self { + match val { NumberBool::True => true, NumberBool::False => false, } @@ -554,7 +557,7 @@ impl FromElem for Algorithm { let file_name: &str = attr_map(e, "name")?; let style = attr_parse(e, "style").ok().unwrap_or(AlgorithmStyle::Keil); Ok(Self { - file_name: file_name.replace("\\", "/").into(), + file_name: file_name.replace('\\', "/").into(), start: attr_parse_hex(e, "start")?, size: attr_parse_hex(e, "size")?, ram_start: attr_parse_hex(e, "RAMstart").ok(), @@ -680,7 +683,7 @@ impl<'dom> DeviceBuilder<'dom> { } } -fn parse_device<'dom>(e: &'dom Element) -> Vec> { +fn parse_device(e: &Element) -> Vec> { let mut device = DeviceBuilder::from_elem(e); let variants = e .children() @@ -723,7 +726,7 @@ fn parse_device<'dom>(e: &'dom Element) -> Vec> { } } -fn parse_sub_family<'dom>(e: &'dom Element) -> Vec> { +fn parse_sub_family(e: &Element) -> Vec> { let mut sub_family_device = DeviceBuilder::from_elem(e); let devices = e .children() @@ -808,14 +811,10 @@ pub struct Devices(pub HashMap); impl FromElem for Devices { fn from_elem(e: &Element) -> Result { e.children() - .fold(Ok(HashMap::new()), |res, c| match (res, parse_family(c)) { - (Ok(mut devs), Ok(add_this)) => { - devs.extend(add_this.into_iter().map(|dev| (dev.name.clone(), dev))); - Ok(devs) - } - (Ok(_), Err(e)) => Err(e), - (Err(e), Ok(_)) => Err(e), - (Err(e), Err(_)) => Err(e), + .try_fold(HashMap::new(), |mut res, c| { + let add_this = parse_family(c)?; + res.extend(add_this.into_iter().map(|dev| (dev.name.clone(), dev))); + Ok(res) }) .map(Devices) } diff --git a/rust/cmsis-pack/src/pdsc/mod.rs b/rust/cmsis-pack/src/pdsc/mod.rs index dd14d491c..108b418ff 100644 --- a/rust/cmsis-pack/src/pdsc/mod.rs +++ b/rust/cmsis-pack/src/pdsc/mod.rs @@ -220,8 +220,8 @@ impl Package { .collect() } - pub fn make_condition_lookup<'a>(&'a self) -> HashMap<&'a str, &'a Condition> { - let mut map = HashMap::with_capacity(self.conditions.0.iter().count()); + pub fn make_condition_lookup(&self) -> HashMap<&str, &Condition> { + let mut map = HashMap::with_capacity(self.conditions.0.len()); for cond in self.conditions.0.iter() { if let Some(dup) = map.insert(cond.id.as_str(), cond) { log::warn!("Duplicate Condition found {}", dup.id); @@ -230,7 +230,7 @@ impl Package { map } - pub fn make_dump_devices<'a>(&'a self) -> Vec<(&'a str, DumpDevice<'a>)> { + pub fn make_dump_devices(&self) -> Vec<(&str, DumpDevice<'_>)> { let from_pack = FromPack::new( &self.vendor, &self.name, diff --git a/rust/cmsis-pack/src/update/download.rs b/rust/cmsis-pack/src/update/download.rs index d2757442b..af1c6e332 100644 --- a/rust/cmsis-pack/src/update/download.rs +++ b/rust/cmsis-pack/src/update/download.rs @@ -16,9 +16,9 @@ use crate::utils::parse::FromElem; use futures::StreamExt; use std::collections::HashMap; -const CONCURRENCY : usize = 32; -const HOST_LIMIT : usize = 6; -const MAX_RETRIES : usize = 3; +const CONCURRENCY: usize = 32; +const HOST_LIMIT: usize = 6; +const MAX_RETRIES: usize = 3; fn pdsc_url(pdsc: &mut PdscRef) -> String { if pdsc.url.ends_with('/') { @@ -32,6 +32,7 @@ pub trait DownloadConfig { fn pack_store(&self) -> PathBuf; } +#[allow(clippy::wrong_self_convention)] pub trait IntoDownload { fn into_uri(&self) -> Result; fn into_fd(&self, _: &D) -> PathBuf; @@ -39,11 +40,8 @@ pub trait IntoDownload { impl IntoDownload for PdscRef { fn into_uri(&self) -> Result { - let &PdscRef { - ref url, - ref vendor, - ref name, - .. + let PdscRef { + url, vendor, name, .. } = self; let uri = if url.ends_with('/') { format!("{}{}.{}.pdsc", url, vendor, name) @@ -55,10 +53,10 @@ impl IntoDownload for PdscRef { } fn into_fd(&self, config: &D) -> PathBuf { - let &PdscRef { - ref vendor, - ref name, - ref version, + let PdscRef { + vendor, + name, + version, .. } = self; let mut filename = config.pack_store(); @@ -68,13 +66,13 @@ impl IntoDownload for PdscRef { } } -impl<'a> IntoDownload for &'a Package { +impl IntoDownload for &Package { fn into_uri(&self) -> Result { - let &Package { - ref name, - ref vendor, - ref url, - ref releases, + let Package { + name, + vendor, + url, + releases, .. } = *self; let version: &str = releases.latest_release().version.as_ref(); @@ -88,10 +86,10 @@ impl<'a> IntoDownload for &'a Package { } fn into_fd(&self, config: &D) -> PathBuf { - let &Package { - ref name, - ref vendor, - ref releases, + let Package { + name, + vendor, + releases, .. } = *self; let version: &str = releases.latest_release().version.as_ref(); @@ -103,10 +101,13 @@ impl<'a> IntoDownload for &'a Package { } } - async fn save_response(response: Response, dest: PathBuf) -> Result<(usize, PathBuf), Error> { let temp = dest.with_extension("part"); - let file = OpenOptions::new().write(true).create(true).open(&temp); + let file = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(&temp); let mut file = match file { Err(err) => return Err(anyhow!(err.to_string())), @@ -138,7 +139,6 @@ async fn save_response(response: Response, dest: PathBuf) -> Result<(usize, Path Ok((fsize, dest)) } - pub trait DownloadProgress: Send { fn size(&self, files: usize); fn progress(&self, bytes: usize); @@ -190,11 +190,8 @@ where .filter_map(|i| { if let Ok(uri) = i.into_uri() { let c = uri.clone(); - if let Some(host) = c.host_str() { - Some((uri, host.to_string(), i.into_fd(self.config))) - } else { - None - } + c.host_str() + .map(|host| (uri, host.to_string(), i.into_fd(self.config))) } else { None } @@ -203,8 +200,8 @@ where self.prog.size(to_dl.len()); let mut hosts: HashMap = HashMap::new(); - let mut results : Vec = vec![]; - let mut started : usize = 0; + let mut results: Vec = vec![]; + let mut started: usize = 0; let mut handles: Vec)>> = vec![]; while !to_dl.is_empty() || !handles.is_empty() { @@ -226,11 +223,11 @@ where } } - while ! to_dl.is_empty() && started < CONCURRENCY { + while !to_dl.is_empty() && started < CONCURRENCY { let from = to_dl.pop().unwrap(); let host = from.1.clone(); let entry = hosts.entry(host).or_insert(0); - if *entry >= HOST_LIMIT { + if *entry >= HOST_LIMIT { wait_list.push(from); } else { let source = from.0.clone(); @@ -240,32 +237,37 @@ where results.push(dest); } else { let client = self.client.clone(); - let handle: JoinHandle<(String, usize, Option)> = tokio::spawn(async move { - dest.parent().map(create_dir_all); - let res = client.get(source.clone()).send().await; - let res: Result<(usize, PathBuf), Error> = match res { - Ok(r) => { - let rc = r.status().as_u16(); - if rc >= 400 { - Err(anyhow!(format!("Response code in invalid range: {}", rc).to_string())) - } else { - save_response(r, dest).await + let handle: JoinHandle<(String, usize, Option)> = + tokio::spawn(async move { + dest.parent().map(create_dir_all); + let res = client.get(source.clone()).send().await; + let res: Result<(usize, PathBuf), Error> = match res { + Ok(r) => { + let rc = r.status().as_u16(); + if rc >= 400 { + Err(anyhow!(format!( + "Response code in invalid range: {}", + rc + ) + .to_string())) + } else { + save_response(r, dest).await + } + } + Err(err) => Err(anyhow!(err.to_string())), + }; + match res { + Ok(r) => (host, r.0, Some(r.1)), + Err(err) => { + log::warn!( + "Download of {} failed: {}", + source.to_string(), + err + ); + (host, 0, None) } - }, - Err(err) => { - Err(anyhow!(err.to_string())) - }, - }; - match res { - Ok(r) => { - (host, r.0, Some(r.1)) - }, - Err(err) => { - log::warn!("Download of {} failed: {}", source.to_string(), err); - (host, 0, None) } - } - }); + }); handles.push(handle); started += 1; *entry += 1; @@ -298,10 +300,7 @@ where loop { // Remove from list all duplicate URLs and those already downloaded urls.dedup(); - urls = urls - .into_iter() - .filter(|u| !*downloaded.get(u).unwrap_or(&false)) - .collect(); + urls.retain(|u| !*downloaded.get(u).unwrap_or(&false)); // TODO: Make this section asynchronous let mut next: Vec = Vec::new(); @@ -339,7 +338,7 @@ where pdscs.append(&mut v.pdsc_index); } - pdscs.dedup_by_key(|pdsc| pdsc_url(pdsc)); + pdscs.dedup_by_key(pdsc_url); log::info!("Found {} Pdsc entries", pdscs.len()); Ok(self.download_iterator(pdscs.into_iter()).await) diff --git a/rust/cmsis-pack/src/update/mod.rs b/rust/cmsis-pack/src/update/mod.rs index 9b6883227..da6e05d02 100644 --- a/rust/cmsis-pack/src/update/mod.rs +++ b/rust/cmsis-pack/src/update/mod.rs @@ -27,7 +27,7 @@ where } /// Flatten a list of Vidx Urls into a list of updated CMSIS packs -pub fn install<'a, I: 'a, P, D>(config: &'a D, pdsc_list: I, progress: P) -> Result> +pub fn install<'a, I, P, D>(config: &'a D, pdsc_list: I, progress: P) -> Result> where I: IntoIterator, P: DownloadProgress + 'a, diff --git a/rust/cmsis-pack/src/utils/parse.rs b/rust/cmsis-pack/src/utils/parse.rs index 4fc402e9a..018c76a0f 100644 --- a/rust/cmsis-pack/src/utils/parse.rs +++ b/rust/cmsis-pack/src/utils/parse.rs @@ -18,21 +18,21 @@ where .ok_or_else(|| format_err!("{} not found in {} element", name, from.name())) } -pub fn attr_parse_hex<'a>(from: &'a Element, name: &str) -> Result { +pub fn attr_parse_hex(from: &Element, name: &str) -> Result { from.attr(name) .ok_or_else(|| format_err!("{} not found in {} element", name, from.name())) .and_then(|st| { - if st.starts_with("0x") { - u64::from_str_radix(&st[2..], 16).map_err(|e| format_err!("{}", e)) - } else if st.starts_with('0') { - u64::from_str_radix(&st[1..], 8).map_err(|e| format_err!("{}", e)) + if let Some(hex) = st.strip_prefix("0x") { + u64::from_str_radix(hex, 16).map_err(|e| format_err!("{}", e)) + } else if let Some(oct) = st.strip_prefix('0') { + u64::from_str_radix(oct, 8).map_err(|e| format_err!("{}", e)) } else { - u64::from_str_radix(st, 10).map_err(|e| format_err!("{}", e)) + st.parse::().map_err(|e| format_err!("{}", e)) } }) } -pub fn attr_parse<'a, T, E>(from: &'a Element, name: &str) -> Result +pub fn attr_parse(from: &Element, name: &str) -> Result where T: FromStr, E: Display, @@ -42,7 +42,7 @@ where .and_then(|st| st.parse::().map_err(|e| format_err!("{}", e))) } -pub fn child_text<'a>(from: &'a Element, name: &str) -> Result { +pub fn child_text(from: &Element, name: &str) -> Result { match get_child_no_ns(from, name) { Some(child) => Ok(child.text()), None => Err(format_err!( @@ -54,12 +54,7 @@ pub fn child_text<'a>(from: &'a Element, name: &str) -> Result { } pub fn get_child_no_ns<'a>(from: &'a Element, name: &str) -> Option<&'a Element> { - for child in from.children() { - if child.name() == name { - return Some(child); - } - } - None + from.children().find(|&child| child.name() == name) } pub fn assert_root_name(from: &Element, name: &str) -> Result<(), Error> { From 776e963792781b245f91879cf3764a921d815085 Mon Sep 17 00:00:00 2001 From: Mathias Brossard Date: Sun, 23 Feb 2025 21:48:57 -0600 Subject: [PATCH 2/2] Migration to roxmltree --- Cargo.lock | 26 ++--- rust/cmsis-pack/Cargo.toml | 4 +- rust/cmsis-pack/src/lib.rs | 2 +- rust/cmsis-pack/src/pack_index/mod.rs | 41 +++++-- rust/cmsis-pack/src/pdsc/component.rs | 52 ++++----- rust/cmsis-pack/src/pdsc/condition.rs | 20 ++-- rust/cmsis-pack/src/pdsc/device.rs | 159 +++++++++++++------------- rust/cmsis-pack/src/pdsc/mod.rs | 61 ++++++---- rust/cmsis-pack/src/utils/parse.rs | 79 +++++++------ rust/cmsis-pack/src/utils/prelude.rs | 2 +- 10 files changed, 238 insertions(+), 208 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 424e0ef9b..8c47c2538 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,8 +106,8 @@ dependencies = [ "bytes", "futures", "log", - "minidom", "reqwest", + "roxmltree", "serde", "serde_json", "tokio", @@ -580,15 +580,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minidom" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe549115a674f5ec64c754d85e37d6f42664bd0ef4ffb62b619489ad99c6cb1a" -dependencies = [ - "quick-xml", -] - [[package]] name = "miniz_oxide" version = "0.8.5" @@ -678,15 +669,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quick-xml" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe1e430bdcf30c9fdc25053b9c459bb1a4672af4617b6c783d7d91dc17c6bbb0" -dependencies = [ - "memchr", -] - [[package]] name = "quinn" version = "0.11.6" @@ -837,6 +819,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + [[package]] name = "rustc-demangle" version = "0.1.24" diff --git a/rust/cmsis-pack/Cargo.toml b/rust/cmsis-pack/Cargo.toml index 2a0dda8c9..b6d872a44 100644 --- a/rust/cmsis-pack/Cargo.toml +++ b/rust/cmsis-pack/Cargo.toml @@ -18,11 +18,11 @@ edition = "2018" bytes = "1.0" futures = "0.3.8" log = "0.4.8" -minidom = "0.12.0" +roxmltree = "0.20.0" serde = { version = "1.0.118", features = ["derive"] } serde_json = "1.0" tokio = { version = "1.0", features = ["macros", "rt"] } -reqwest = { version = "0.12.0", default_features = false, features = [ +reqwest = { version = "0.12.0", default-features = false, features = [ "rustls-tls-native-roots", "trust-dns", "stream", diff --git a/rust/cmsis-pack/src/lib.rs b/rust/cmsis-pack/src/lib.rs index a3c842975..7a38b184b 100644 --- a/rust/cmsis-pack/src/lib.rs +++ b/rust/cmsis-pack/src/lib.rs @@ -8,8 +8,8 @@ pub mod utils; extern crate futures; extern crate log; -extern crate minidom; extern crate reqwest; +extern crate roxmltree; extern crate serde; extern crate serde_json; extern crate tokio; diff --git a/rust/cmsis-pack/src/pack_index/mod.rs b/rust/cmsis-pack/src/pack_index/mod.rs index 1008b47f2..7dfb1f9fa 100644 --- a/rust/cmsis-pack/src/pack_index/mod.rs +++ b/rust/cmsis-pack/src/pack_index/mod.rs @@ -1,6 +1,6 @@ use crate::utils::prelude::*; use anyhow::Error; -use minidom::Element; +use roxmltree::Node; #[derive(Debug, Clone)] pub struct PdscRef { @@ -31,7 +31,7 @@ pub struct Vidx { } impl FromElem for PdscRef { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { assert_root_name(e, "pdsc")?; Ok(Self { url: attr_map(e, "url")?, @@ -47,7 +47,7 @@ impl FromElem for PdscRef { } impl FromElem for Pidx { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { assert_root_name(e, "pidx")?; Ok(Self { url: attr_map(e, "url")?, @@ -58,20 +58,35 @@ impl FromElem for Pidx { } impl FromElem for Vidx { - fn from_elem(root: &Element) -> Result { + fn from_elem(root: &Node) -> Result { assert_root_name(root, "index")?; let vendor = child_text(root, "vendor")?; let url = child_text(root, "url")?; + + let mut timestamp: Option = None; + let mut vendor_index: Vec = Vec::new(); + let mut pdsc_index: Vec = Vec::new(); + for child in root.children() { + match child.tag_name().name() { + "timestamp" => { + timestamp = Some(child).map(|e| e.text().unwrap_or_default().to_string()) + } + "vindex" => { + vendor_index = Pidx::vec_from_children(child.children()); + } + "pindex" => { + pdsc_index = PdscRef::vec_from_children(child.children()); + } + _ => continue, + } + } + Ok(Vidx { vendor, url, - timestamp: get_child_no_ns(root, "timestamp").map(Element::text), - vendor_index: get_child_no_ns(root, "vindex") - .map(|e| Pidx::vec_from_children(e.children())) - .unwrap_or_default(), - pdsc_index: get_child_no_ns(root, "pindex") - .map(|e| PdscRef::vec_from_children(e.children())) - .unwrap_or_default(), + timestamp, + vendor_index, + pdsc_index, }) } } @@ -200,5 +215,9 @@ mod test { let response = Vidx::from_string(good_string).unwrap(); assert_eq!(response.vendor, String::from("Vendor")); assert_eq!(response.url, "Url"); + assert_eq!( + response.timestamp, + Some(String::from("Fri Sep 1 13:26:41 CDT")) + ); } } diff --git a/rust/cmsis-pack/src/pdsc/component.rs b/rust/cmsis-pack/src/pdsc/component.rs index fa2dbf410..9b1d8c88a 100644 --- a/rust/cmsis-pack/src/pdsc/component.rs +++ b/rust/cmsis-pack/src/pdsc/component.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use std::str::FromStr; use anyhow::{format_err, Error}; -use minidom::Element; +use roxmltree::Node; use serde::Serialize; use crate::utils::prelude::*; @@ -79,7 +79,7 @@ pub struct FileRef { } impl FromElem for FileRef { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { assert_root_name(e, "file")?; Ok(Self { path: attr_map(e, "name")?, @@ -112,7 +112,7 @@ pub struct ComponentBuilder { } impl FromElem for ComponentBuilder { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { assert_root_name(e, "component")?; let vendor: Option = attr_map(e, "Cvendor").ok(); let class: Option = attr_map(e, "Cclass").ok(); @@ -122,18 +122,18 @@ impl FromElem for ComponentBuilder { let class_string = class.clone().unwrap_or_else(|| "Class".into()); let group_string = group.clone().unwrap_or_else(|| "Group".into()); let sub_group_string = sub_group.clone().unwrap_or_else(|| "SubGroup".into()); - let files = get_child_no_ns(e, "files") - .map(move |child| { - log::debug!( - "Working on {}::{}::{}::{}", - vendor_string, - class_string, - group_string, - sub_group_string, - ); - FileRef::vec_from_children(child.children()) - }) - .unwrap_or_default(); + let files = if let Some(node) = e.children().find(|c| c.tag_name().name() == "files") { + log::debug!( + "Working on {}::{}::{}::{}", + vendor_string, + class_string, + group_string, + sub_group_string, + ); + FileRef::vec_from_children(node.children()) + } else { + Vec::new() + }; Ok(Self { vendor, class, @@ -187,7 +187,7 @@ impl Bundle { } impl FromElem for Bundle { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { assert_root_name(e, "bundle")?; let name: String = attr_map(e, "Cbundle")?; let class: String = attr_map(e, "Cclass")?; @@ -198,8 +198,8 @@ impl FromElem for Bundle { let components = e .children() .filter_map(move |chld| { - if chld.name() == "component" { - ComponentBuilder::from_elem(chld).ok() + if chld.tag_name().name() == "component" { + ComponentBuilder::from_elem(&chld).ok() } else { None } @@ -217,10 +217,8 @@ impl FromElem for Bundle { } } -fn child_to_component_iter( - e: &Element, -) -> Result>, Error> { - match e.name() { +fn child_to_component_iter(e: &Node) -> Result>, Error> { + match e.tag_name().name() { "bundle" => { let bundle = Bundle::from_elem(e)?; Ok(Box::new(bundle.into_components().into_iter())) @@ -230,8 +228,9 @@ fn child_to_component_iter( Ok(Box::new(Some(component).into_iter())) } _ => Err(format_err!( - "element of name {} is not allowed as a descendant of components", - e.name() + "element of name {} is not allowed as a descendant of components ({:?})", + e.tag_name().name(), + e )), } } @@ -240,11 +239,12 @@ fn child_to_component_iter( pub struct ComponentBuilders(pub(crate) Vec); impl FromElem for ComponentBuilders { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { assert_root_name(e, "components")?; Ok(ComponentBuilders( e.children() - .flat_map(move |c| match child_to_component_iter(c) { + .filter(|e| e.is_element()) + .flat_map(move |c| match child_to_component_iter(&c) { Ok(iter) => iter, Err(e) => { log::error!("when trying to parse component: {}", e); diff --git a/rust/cmsis-pack/src/pdsc/condition.rs b/rust/cmsis-pack/src/pdsc/condition.rs index fd43c59d4..ebd9982a6 100644 --- a/rust/cmsis-pack/src/pdsc/condition.rs +++ b/rust/cmsis-pack/src/pdsc/condition.rs @@ -1,5 +1,5 @@ use anyhow::Error; -use minidom::Element; +use roxmltree::Node; use crate::utils::prelude::*; @@ -12,7 +12,7 @@ pub struct ConditionComponent { } impl FromElem for ConditionComponent { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { Ok(ConditionComponent { device_family: attr_map(e, "Dfamily").ok(), device_sub_family: attr_map(e, "Dsubfamily").ok(), @@ -31,13 +31,13 @@ pub struct Condition { } impl FromElem for Condition { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { assert_root_name(e, "condition")?; let mut accept = Vec::new(); let mut deny = Vec::new(); let mut require = Vec::new(); - for elem in e.children() { - match elem.name() { + for elem in e.children().filter(|e| e.is_element()) { + match elem.tag_name().name() { "accept" => { accept.push(ConditionComponent::from_elem(e)?); } @@ -49,7 +49,10 @@ impl FromElem for Condition { } "description" => {} _ => { - log::warn!("Found unkonwn element {} in components", elem.name()); + log::warn!( + "Found unkonwn element {} in components", + elem.tag_name().name() + ); } } } @@ -66,11 +69,12 @@ impl FromElem for Condition { pub struct Conditions(pub Vec); impl FromElem for Conditions { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { assert_root_name(e, "conditions")?; Ok(Conditions( e.children() - .flat_map(|c| Condition::from_elem(c).ok_warn()) + .filter(|e| e.is_element()) + .flat_map(|c| Condition::from_elem(&c).ok_warn()) .collect(), )) } diff --git a/rust/cmsis-pack/src/pdsc/device.rs b/rust/cmsis-pack/src/pdsc/device.rs index 03c088744..c1c229849 100644 --- a/rust/cmsis-pack/src/pdsc/device.rs +++ b/rust/cmsis-pack/src/pdsc/device.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use crate::utils::prelude::*; use anyhow::{format_err, Error}; -use minidom::{Element, NSChoice}; +use roxmltree::Node; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -166,8 +166,6 @@ impl ProcessorBuilder { let units = self.units.unwrap_or(1); let name = self.name.clone(); - - (0..units) .map(|unit| { // The attributes we're interested in may be spread across multiple debug @@ -214,7 +212,7 @@ impl ProcessorBuilder { } impl FromElem for ProcessorBuilder { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { Ok(ProcessorBuilder { core: attr_parse(e, "Dcore").ok(), units: attr_parse(e, "Punits").ok(), @@ -256,7 +254,7 @@ impl ProcessorsBuilder { } impl FromElem for ProcessorsBuilder { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { Ok(ProcessorsBuilder(vec![ProcessorBuilder::from_elem(e)?])) } } @@ -308,28 +306,30 @@ impl DebugBuilder { } impl DebugBuilder { - fn from_elem_and_parent(e: &Element, p: &Element) -> Result { - let (dp, ap) = if p.has_child("accessportV1", NSChoice::None) - || p.has_child("accessportV2", NSChoice::None) - { + fn from_elem_and_parent(e: &Node, p: &Node) -> Result { + let c = p + .children() + .map(|n| n.tag_name().name()) + .collect::>(); + let (dp, ap) = if c.contains(&"accessportV1") || c.contains(&"accessportV2") { let __apid: u32 = attr_parse(e, "__apid")?; let ap = p .children() .find(|c| { - c.name().starts_with("accessportV") + c.tag_name().name().starts_with("accessportV") && attr_parse(c, "__apid") .map(|apid: u32| apid == __apid) .unwrap_or(false) }) .ok_or_else(|| anyhow::anyhow!("Unable do find Access Port with id {__apid:?}."))?; - match ap.name() { + match ap.tag_name().name() { "accessportV1" => ( - attr_parse(ap, "__dp").ok(), - attr_parse(ap, "index").ok().map(AccessPort::Index), + attr_parse(&ap, "__dp").ok(), + attr_parse(&ap, "index").ok().map(AccessPort::Index), ), "accessportV2" => ( - attr_parse(ap, "__dp").ok(), - attr_parse_hex(ap, "address").ok().map(AccessPort::Address), + attr_parse(&ap, "__dp").ok(), + attr_parse_hex(&ap, "address").ok().map(AccessPort::Address), ), _ => unreachable!(), } @@ -356,7 +356,7 @@ impl DebugBuilder { struct DebugsBuilder(Vec); impl DebugsBuilder { - fn from_elem_and_parent(e: &Element, p: &Element) -> Result { + fn from_elem_and_parent(e: &Node, p: &Node) -> Result { Ok(DebugsBuilder(vec![DebugBuilder::from_elem_and_parent( e, p, )?])) @@ -459,9 +459,9 @@ pub struct Memory { struct MemElem(String, Memory); impl FromElem for MemElem { - fn from_elem(e: &Element) -> Result { - let access = MemoryPermissions::from_str(e.attr("access").unwrap_or_else(|| { - let memtype = e.attr("id").unwrap_or_default(); + fn from_elem(e: &Node) -> Result { + let access = MemoryPermissions::from_str(e.attribute("access").unwrap_or_else(|| { + let memtype = e.attribute("id").unwrap_or_default(); if memtype.contains("ROM") { "rx" } else if memtype.contains("RAM") { @@ -471,11 +471,11 @@ impl FromElem for MemElem { } })); let name = e - .attr("id") - .or_else(|| e.attr("name")) + .attribute("id") + .or_else(|| e.attribute("name")) .map(|s| s.to_string()) .ok_or_else(|| format_err!("No name found for memory"))?; - let p_name = e.attr("Pname").map(|s| s.to_string()); + let p_name = e.attribute("Pname").map(|s| s.to_string()); let start = attr_parse_hex(e, "start")?; let size = attr_parse_hex(e, "size")?; let startup = attr_parse(e, "startup") @@ -549,7 +549,7 @@ pub struct Algorithm { } impl FromElem for Algorithm { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { let default = attr_parse(e, "default") .map(|nb: NumberBool| nb.into()) .unwrap_or_default(); @@ -569,15 +569,15 @@ impl FromElem for Algorithm { } #[derive(Debug)] -struct DeviceBuilder<'dom> { - name: Option<&'dom str>, +struct DeviceBuilder { + name: Option, algorithms: Vec, memories: Memories, processor: Option, debugs: DebugsBuilder, - vendor: Option<&'dom str>, - family: Option<&'dom str>, - sub_family: Option<&'dom str>, + vendor: Option, + family: Option, + sub_family: Option, } #[derive(Debug, Serialize)] @@ -591,20 +591,24 @@ pub struct Device { pub sub_family: Option, } -impl<'dom> DeviceBuilder<'dom> { - fn from_elem(e: &'dom Element) -> Self { +impl DeviceBuilder { + fn from_elem(e: &Node) -> Self { let memories = Memories(HashMap::new()); let mut family = None; let mut sub_family = None; - if e.name() == "family" { - family = e.attr("Dfamily"); + if e.tag_name().name() == "family" { + family = e.attribute("Dfamily").map(|f| f.to_string()); } - if e.name() == "subFamily" { - sub_family = e.attr("DsubFamily"); + if e.tag_name().name() == "subFamily" { + sub_family = e.attribute("DsubFamily").map(|f| f.to_string()); } + DeviceBuilder { - name: e.attr("Dname").or_else(|| e.attr("Dvariant")), - vendor: e.attr("Dvendor"), + name: e + .attribute("Dname") + .or_else(|| e.attribute("Dvariant")) + .map(|f| f.to_string()), + vendor: e.attribute("Dvendor").map(|f| f.to_string()), memories, algorithms: Vec::new(), processor: None, @@ -617,11 +621,9 @@ impl<'dom> DeviceBuilder<'dom> { fn build(self) -> Result { let name = self .name - .map(|s| s.into()) .ok_or_else(|| format_err!("Device found without a name"))?; let family = self .family - .map(|s| s.into()) .ok_or_else(|| format_err!("Device found without a family"))?; let debugs = self.debugs.build(); @@ -636,16 +638,16 @@ impl<'dom> DeviceBuilder<'dom> { name, memories: self.memories, algorithms: self.algorithms, - vendor: self.vendor.map(str::to_string), + vendor: self.vendor, family, - sub_family: self.sub_family.map(str::to_string), + sub_family: self.sub_family, }) } fn add_parent(mut self, parent: &Self) -> Result { self.algorithms.extend_from_slice(&parent.algorithms); Ok(Self { - name: self.name.or(parent.name), + name: self.name.or(parent.name.clone()), algorithms: self.algorithms, memories: merge_memories(self.memories, &parent.memories), processor: match self.processor { @@ -653,9 +655,9 @@ impl<'dom> DeviceBuilder<'dom> { None => parent.processor.clone(), }, debugs: self.debugs.merge(&parent.debugs), - vendor: self.vendor.or(parent.vendor), - family: self.family.or(parent.family), - sub_family: self.sub_family.or(parent.sub_family), + vendor: self.vendor.or(parent.vendor.clone()), + family: self.family.or(parent.family.clone()), + sub_family: self.sub_family.or(parent.sub_family.clone()), }) } @@ -683,32 +685,32 @@ impl<'dom> DeviceBuilder<'dom> { } } -fn parse_device(e: &Element) -> Vec> { +fn parse_device(e: &Node) -> Vec { let mut device = DeviceBuilder::from_elem(e); - let variants = e + let variants: Vec = e .children() - .filter_map(|child| match child.name() { - "variant" => Some(DeviceBuilder::from_elem(child)), + .filter_map(|child| match child.tag_name().name() { + "variant" => Some(DeviceBuilder::from_elem(&child)), "memory" => { - FromElem::from_elem(child) + FromElem::from_elem(&child) .ok_warn() .map(|mem| device.add_memory(mem)); None } "algorithm" => { - FromElem::from_elem(child) + FromElem::from_elem(&child) .ok_warn() .map(|alg| device.add_algorithm(alg)); None } "processor" => { - FromElem::from_elem(child) + FromElem::from_elem(&child) .ok_warn() .map(|prc| device.add_processor(prc)); None } "debug" => { - DebugsBuilder::from_elem_and_parent(child, e) + DebugsBuilder::from_elem_and_parent(&child, e) .ok_warn() .map(|debug| device.add_debug(debug)); None @@ -726,72 +728,71 @@ fn parse_device(e: &Element) -> Vec> { } } -fn parse_sub_family(e: &Element) -> Vec> { +fn parse_sub_family(e: &Node) -> Vec { let mut sub_family_device = DeviceBuilder::from_elem(e); - let devices = e - .children() - .flat_map(|child| match child.name() { - "device" => parse_device(child), + let mut devices: Vec = Vec::new(); + + for child in e.children() { + match child.tag_name().name() { + "device" => { + devices.extend(parse_device(&child)); + } "memory" => { - FromElem::from_elem(child) + FromElem::from_elem(&child) .ok_warn() .map(|mem| sub_family_device.add_memory(mem)); - Vec::new() } "algorithm" => { - FromElem::from_elem(child) + FromElem::from_elem(&child) .ok_warn() .map(|alg| sub_family_device.add_algorithm(alg)); - Vec::new() } "processor" => { - FromElem::from_elem(child) + FromElem::from_elem(&child) .ok_warn() .map(|prc| sub_family_device.add_processor(prc)); - Vec::new() } "debug" => { - DebugsBuilder::from_elem_and_parent(child, e) + DebugsBuilder::from_elem_and_parent(&child, e) .ok_warn() .map(|debug| sub_family_device.add_debug(debug)); - Vec::new() } - _ => Vec::new(), - }) - .collect::>(); + _ => continue, + } + } devices .into_iter() .flat_map(|bldr| bldr.add_parent(&sub_family_device).ok_warn()) .collect() } -fn parse_family(e: &Element) -> Result, Error> { +fn parse_family(e: &Node) -> Result, Error> { let mut family_device = DeviceBuilder::from_elem(e); - let all_devices = e + let all_devices: Vec = e .children() - .flat_map(|child| match child.name() { - "subFamily" => parse_sub_family(child), - "device" => parse_device(child), + .flat_map(|child| match child.tag_name().name() { + "subFamily" => parse_sub_family(&child), + "device" => parse_device(&child), "memory" => { - FromElem::from_elem(child) + FromElem::from_elem(&child) .ok_warn() .map(|mem| family_device.add_memory(mem)); Vec::new() } "algorithm" => { - FromElem::from_elem(child) + FromElem::from_elem(&child) .ok_warn() .map(|alg| family_device.add_algorithm(alg)); Vec::new() } "processor" => { - FromElem::from_elem(child) + FromElem::from_elem(&child) .ok_warn() .map(|prc| family_device.add_processor(prc)); Vec::new() } "debug" => { - DebugsBuilder::from_elem_and_parent(child, e) + DebugsBuilder::from_elem_and_parent(&child, e) .ok_warn() .map(|debug| family_device.add_debug(debug)); Vec::new() @@ -809,10 +810,10 @@ fn parse_family(e: &Element) -> Result, Error> { pub struct Devices(pub HashMap); impl FromElem for Devices { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { e.children() .try_fold(HashMap::new(), |mut res, c| { - let add_this = parse_family(c)?; + let add_this = parse_family(&c)?; res.extend(add_this.into_iter().map(|dev| (dev.name.clone(), dev))); Ok(res) }) diff --git a/rust/cmsis-pack/src/pdsc/mod.rs b/rust/cmsis-pack/src/pdsc/mod.rs index 108b418ff..b990c5ce9 100644 --- a/rust/cmsis-pack/src/pdsc/mod.rs +++ b/rust/cmsis-pack/src/pdsc/mod.rs @@ -1,4 +1,4 @@ -use minidom::Element; +use roxmltree::Node; use serde::{Deserialize, Serialize}; use std::borrow::Cow; use std::collections::{BTreeMap, HashMap}; @@ -22,11 +22,11 @@ pub struct Release { } impl FromElem for Release { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { assert_root_name(e, "release")?; Ok(Self { version: attr_map(e, "version")?, - text: e.text(), + text: e.text().unwrap().to_string(), }) } } @@ -41,11 +41,12 @@ impl Releases { } impl FromElem for Releases { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { assert_root_name(e, "releases")?; let to_ret: Vec<_> = e .children() - .flat_map(|c| Release::from_elem(c).ok_warn()) + .filter(|e| e.is_element()) + .flat_map(|c| Release::from_elem(&c).ok_warn()) .collect(); if to_ret.is_empty() { Err(format_err!("There must be at least one release!")) @@ -115,28 +116,40 @@ pub struct Package { } impl FromElem for Package { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { assert_root_name(e, "package")?; let name: String = child_text(e, "name")?; let description: String = child_text(e, "description")?; let vendor: String = child_text(e, "vendor")?; let url: String = child_text(e, "url")?; log::debug!("Working on {}::{}", vendor, name,); - let components = get_child_no_ns(e, "components") - .and_then(|c| ComponentBuilders::from_elem(c).ok_warn()) - .unwrap_or_default(); - let releases = get_child_no_ns(e, "releases") - .and_then(|c| Releases::from_elem(c).ok_warn()) - .unwrap_or_default(); - let conditions = get_child_no_ns(e, "conditions") - .and_then(|c| Conditions::from_elem(c).ok_warn()) - .unwrap_or_default(); - let devices = get_child_no_ns(e, "devices") - .and_then(|c| Devices::from_elem(c).ok_warn()) - .unwrap_or_default(); - let boards = get_child_no_ns(e, "boards") - .map(|c| Board::vec_from_children(c.children())) - .unwrap_or_default(); + let mut components = ComponentBuilders::default(); + let mut releases = Releases::default(); + let mut conditions = Conditions::default(); + let mut devices = Devices::default(); + let mut boards: Vec = Vec::new(); + for child in e.children() { + match child.tag_name().name() { + "components" => { + components = ComponentBuilders::from_elem(&child) + .ok_warn() + .unwrap_or_default(); + } + "releases" => { + releases = Releases::from_elem(&child).ok_warn().unwrap_or_default(); + } + "conditions" => { + conditions = Conditions::from_elem(&child).ok_warn().unwrap_or_default(); + } + "devices" => { + devices = Devices::from_elem(&child).ok_warn().unwrap_or_default(); + } + "boards" => { + boards = Board::vec_from_children(child.children()); + } + _ => {} + } + } Ok(Self { name, description, @@ -159,13 +172,13 @@ pub struct Board { } impl FromElem for Board { - fn from_elem(e: &Element) -> Result { + fn from_elem(e: &Node) -> Result { Ok(Self { name: attr_map(e, "name")?, mounted_devices: e .children() - .flat_map(|c| match c.name() { - "mountedDevice" => attr_map(c, "Dname").ok(), + .flat_map(|c| match c.tag_name().name() { + "mountedDevice" => attr_map(&c, "Dname").ok(), _ => None, }) .collect(), diff --git a/rust/cmsis-pack/src/utils/parse.rs b/rust/cmsis-pack/src/utils/parse.rs index 018c76a0f..c2307887e 100644 --- a/rust/cmsis-pack/src/utils/parse.rs +++ b/rust/cmsis-pack/src/utils/parse.rs @@ -1,26 +1,26 @@ use std::fmt::Display; -use std::io::BufRead; +use std::fs::File; +use std::io::{BufRead, BufReader}; use std::path::Path; use std::str::FromStr; use crate::utils::ResultLogExt; -use minidom::quick_xml::Reader; -use minidom::{Children, Element}; +use roxmltree::{Children, Node}; use anyhow::{format_err, Error}; -pub fn attr_map<'a, T>(from: &'a Element, name: &str) -> Result +pub fn attr_map<'a, T>(from: &'a Node, name: &str) -> Result where T: From<&'a str>, { - from.attr(name) + from.attribute(name) .map(T::from) - .ok_or_else(|| format_err!("{} not found in {} element", name, from.name())) + .ok_or_else(|| format_err!("{} not found in {} element", name, from.tag_name().name())) } -pub fn attr_parse_hex(from: &Element, name: &str) -> Result { - from.attr(name) - .ok_or_else(|| format_err!("{} not found in {} element", name, from.name())) +pub fn attr_parse_hex(from: &Node, name: &str) -> Result { + from.attribute(name) + .ok_or_else(|| format_err!("{} not found in {} element", name, from.tag_name().name())) .and_then(|st| { if let Some(hex) = st.strip_prefix("0x") { u64::from_str_radix(hex, 16).map_err(|e| format_err!("{}", e)) @@ -32,37 +32,36 @@ pub fn attr_parse_hex(from: &Element, name: &str) -> Result { }) } -pub fn attr_parse(from: &Element, name: &str) -> Result +pub fn attr_parse(from: &Node, name: &str) -> Result where T: FromStr, E: Display, { - from.attr(name) - .ok_or_else(|| format_err!("{} not found in {} element", name, from.name())) + from.attribute(name) + .ok_or_else(|| format_err!("{} not found in {} element", name, from.tag_name().name())) .and_then(|st| st.parse::().map_err(|e| format_err!("{}", e))) } -pub fn child_text(from: &Element, name: &str) -> Result { - match get_child_no_ns(from, name) { - Some(child) => Ok(child.text()), - None => Err(format_err!( - "child element \"{}\" not found in \"{}\" element", - name, - from.name() - )), +pub fn child_text(from: &Node, name: &str) -> Result { + for child in from.children() { + if child.tag_name().name() == name { + return Ok(child.text().unwrap_or_default().to_string()); + } } + Err(format_err!( + "child element \"{}\" not found in \"{}\" element", + name, + from.tag_name().name() + )) } -pub fn get_child_no_ns<'a>(from: &'a Element, name: &str) -> Option<&'a Element> { - from.children().find(|&child| child.name() == name) -} - -pub fn assert_root_name(from: &Element, name: &str) -> Result<(), Error> { - if from.name() != name { +pub fn assert_root_name(from: &Node, name: &str) -> Result<(), Error> { + if from.tag_name().name() != name { Err(format_err!( - "tried to parse element \"{}\" from element \"{}\"", + "tried to parse element \"{}\" from element \"{}\" \"{:?}\"", name, - from.name() + from.tag_name().name(), + from, )) } else { Ok(()) @@ -70,23 +69,29 @@ pub fn assert_root_name(from: &Element, name: &str) -> Result<(), Error> { } pub trait FromElem: Sized { - fn from_elem(e: &Element) -> Result; + fn from_elem(e: &Node) -> Result; - fn from_reader(r: &mut Reader) -> Result { - let mut root = Element::from_reader(r)?; - root.set_attr::<&str, Option>("xmlns:xs", None); + fn from_string(s: &str) -> Result { + let doc = roxmltree::Document::parse(s)?; + let root = doc.root_element(); Self::from_elem(&root) } - fn from_string(s: &str) -> Result { - let mut r = Reader::from_str(s); - Self::from_reader(&mut r) + + fn from_reader(r: &mut T) -> Result { + let mut xml_str = String::new(); + r.read_to_string(&mut xml_str)?; + Self::from_string(&xml_str) } + fn from_path(p: &Path) -> Result { - let mut r = Reader::from_file(p)?; + let f = File::open(p)?; + let mut r = BufReader::new(f); Self::from_reader(&mut r) } + fn vec_from_children(clds: Children) -> Vec { - clds.flat_map(move |cld| Self::from_elem(cld).ok_warn().into_iter()) + clds.filter(|e| e.is_element()) + .flat_map(move |cld| Self::from_elem(&cld).ok_warn().into_iter()) .collect() } } diff --git a/rust/cmsis-pack/src/utils/prelude.rs b/rust/cmsis-pack/src/utils/prelude.rs index 430dc452f..476aee4fd 100644 --- a/rust/cmsis-pack/src/utils/prelude.rs +++ b/rust/cmsis-pack/src/utils/prelude.rs @@ -1,4 +1,4 @@ pub use super::parse::{ - assert_root_name, attr_map, attr_parse, attr_parse_hex, child_text, get_child_no_ns, FromElem, + assert_root_name, attr_map, attr_parse, attr_parse_hex, child_text, FromElem, }; pub use super::ResultLogExt;