cmsis_pack/utils/
parse.rs1use std::fmt::Display;
2use std::fs::File;
3use std::io::{BufRead, BufReader};
4use std::path::Path;
5use std::str::FromStr;
6
7use crate::utils::ResultLogExt;
8use roxmltree::{Children, Node};
9
10use anyhow::{format_err, Error};
11
12pub fn attr_map<'a, T>(from: &'a Node, name: &str) -> Result<T, Error>
13where
14 T: From<&'a str>,
15{
16 from.attribute(name)
17 .map(T::from)
18 .ok_or_else(|| format_err!("{} not found in {} element", name, from.tag_name().name()))
19}
20
21pub fn attr_parse_hex(from: &Node, name: &str) -> Result<u64, Error> {
22 from.attribute(name)
23 .ok_or_else(|| format_err!("{} not found in {} element", name, from.tag_name().name()))
24 .and_then(|st| {
25 if let Some(hex) = st.strip_prefix("0x") {
26 u64::from_str_radix(hex, 16).map_err(|e| format_err!("{}", e))
27 } else if let Some(oct) = st.strip_prefix('0') {
28 u64::from_str_radix(oct, 8).map_err(|e| format_err!("{}", e))
29 } else {
30 st.parse::<u64>().map_err(|e| format_err!("{}", e))
31 }
32 })
33}
34
35pub fn attr_parse<T, E>(from: &Node, name: &str) -> Result<T, Error>
36where
37 T: FromStr<Err = E>,
38 E: Display,
39{
40 from.attribute(name)
41 .ok_or_else(|| format_err!("{} not found in {} element", name, from.tag_name().name()))
42 .and_then(|st| st.parse::<T>().map_err(|e| format_err!("{}", e)))
43}
44
45pub fn child_text(from: &Node, name: &str) -> Result<String, Error> {
46 for child in from.children() {
47 if child.tag_name().name() == name {
48 return Ok(child.text().unwrap_or_default().to_string());
49 }
50 }
51 Err(format_err!(
52 "child element \"{}\" not found in \"{}\" element",
53 name,
54 from.tag_name().name()
55 ))
56}
57
58pub fn assert_root_name(from: &Node, name: &str) -> Result<(), Error> {
59 if from.tag_name().name() != name {
60 Err(format_err!(
61 "tried to parse element \"{}\" from element \"{}\" \"{:?}\"",
62 name,
63 from.tag_name().name(),
64 from,
65 ))
66 } else {
67 Ok(())
68 }
69}
70
71pub trait FromElem: Sized {
72 fn from_elem(e: &Node) -> Result<Self, Error>;
73
74 fn from_string(s: &str) -> Result<Self, Error> {
75 let doc = roxmltree::Document::parse(s)?;
76 let root = doc.root_element();
77 Self::from_elem(&root)
78 }
79
80 fn from_reader<T: BufRead>(r: &mut T) -> Result<Self, Error> {
81 let mut xml_str = String::new();
82 r.read_to_string(&mut xml_str)?;
83 Self::from_string(&xml_str)
84 }
85
86 fn from_path(p: &Path) -> Result<Self, Error> {
87 let f = File::open(p)?;
88 let mut r = BufReader::new(f);
89 Self::from_reader(&mut r)
90 }
91
92 fn vec_from_children(clds: Children) -> Vec<Self> {
93 clds.filter(|e| e.is_element())
94 .flat_map(move |cld| Self::from_elem(&cld).ok_warn().into_iter())
95 .collect()
96 }
97}