cmsis_pack/utils/
parse.rs

1use 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}