cmsis_pack/pdsc/
component.rs

1use std::path::PathBuf;
2use std::str::FromStr;
3
4use anyhow::{format_err, Error};
5use roxmltree::Node;
6use serde::Serialize;
7
8use crate::utils::prelude::*;
9
10#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
11pub enum FileCategory {
12    Doc,
13    Header,
14    Include,
15    Library,
16    Object,
17    Source,
18    SourceC,
19    SourceCpp,
20    SourceAsm,
21    LinkerScript,
22    Utility,
23    Image,
24    PreIncludeGlobal,
25    PreIncludeLocal,
26    Other,
27}
28
29impl FromStr for FileCategory {
30    type Err = Error;
31    fn from_str(from: &str) -> Result<Self, Error> {
32        match from {
33            "doc" => Ok(FileCategory::Doc),
34            "header" => Ok(FileCategory::Header),
35            "include" => Ok(FileCategory::Include),
36            "library" => Ok(FileCategory::Library),
37            "object" => Ok(FileCategory::Object),
38            "source" => Ok(FileCategory::Source),
39            "sourceC" => Ok(FileCategory::SourceC),
40            "sourceCpp" => Ok(FileCategory::SourceCpp),
41            "sourceAsm" => Ok(FileCategory::SourceAsm),
42            "linkerScript" => Ok(FileCategory::LinkerScript),
43            "utility" => Ok(FileCategory::Utility),
44            "image" => Ok(FileCategory::Image),
45            "preIncludeGlobal" => Ok(FileCategory::PreIncludeGlobal),
46            "preIncludeLocal" => Ok(FileCategory::PreIncludeLocal),
47            "other" => Ok(FileCategory::Other),
48            unknown => Err(format_err!("Unknown file category {}", unknown)),
49        }
50    }
51}
52
53#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
54pub enum FileAttribute {
55    Config,
56    Template,
57}
58
59impl FromStr for FileAttribute {
60    type Err = Error;
61    fn from_str(from: &str) -> Result<Self, Error> {
62        match from {
63            "config" => Ok(FileAttribute::Config),
64            "template" => Ok(FileAttribute::Template),
65            unknown => Err(format_err!("Unknown file attribute {}", unknown)),
66        }
67    }
68}
69
70#[derive(Debug, Clone, Serialize)]
71pub struct FileRef {
72    pub path: PathBuf,
73    category: FileCategory,
74    attr: Option<FileAttribute>,
75    pub condition: Option<String>,
76    select: Option<String>,
77    src: Option<String>,
78    version: Option<String>,
79}
80
81impl FromElem for FileRef {
82    fn from_elem(e: &Node) -> Result<Self, Error> {
83        assert_root_name(e, "file")?;
84        Ok(Self {
85            path: attr_map(e, "name")?,
86            category: attr_parse(e, "category")?,
87            attr: attr_parse(e, "attr").ok(),
88            condition: attr_map(e, "condition").ok(),
89            select: attr_map(e, "select").ok(),
90            src: attr_map(e, "src").ok(),
91            version: attr_map(e, "version").ok(),
92        })
93    }
94}
95
96#[derive(Debug, Clone, Serialize)]
97pub struct ComponentBuilder {
98    pub vendor: Option<String>,
99    pub class: Option<String>,
100    pub group: Option<String>,
101    pub sub_group: Option<String>,
102    pub variant: Option<String>,
103    pub version: Option<String>,
104    pub api_version: Option<String>,
105    pub condition: Option<String>,
106    pub max_instances: Option<u8>,
107    pub is_default: bool,
108    pub deprecated: bool,
109    pub description: String,
110    pub rte_addition: String,
111    pub files: Vec<FileRef>,
112}
113
114impl FromElem for ComponentBuilder {
115    fn from_elem(e: &Node) -> Result<Self, Error> {
116        assert_root_name(e, "component")?;
117        let vendor: Option<String> = attr_map(e, "Cvendor").ok();
118        let class: Option<String> = attr_map(e, "Cclass").ok();
119        let group: Option<String> = attr_map(e, "Cgroup").ok();
120        let sub_group: Option<String> = attr_map(e, "Csub").ok();
121        let vendor_string = vendor.clone().unwrap_or_else(|| "Vendor".into());
122        let class_string = class.clone().unwrap_or_else(|| "Class".into());
123        let group_string = group.clone().unwrap_or_else(|| "Group".into());
124        let sub_group_string = sub_group.clone().unwrap_or_else(|| "SubGroup".into());
125        let files = if let Some(node) = e.children().find(|c| c.tag_name().name() == "files") {
126            log::debug!(
127                "Working on {}::{}::{}::{}",
128                vendor_string,
129                class_string,
130                group_string,
131                sub_group_string,
132            );
133            FileRef::vec_from_children(node.children())
134        } else {
135            Vec::new()
136        };
137        Ok(Self {
138            vendor,
139            class,
140            group,
141            sub_group,
142            version: attr_map(e, "Cversion").ok(),
143            variant: attr_map(e, "Cvariant").ok(),
144            api_version: attr_map(e, "Capiversion").ok(),
145            condition: attr_map(e, "condition").ok(),
146            max_instances: attr_parse(e, "maxInstances").ok(),
147            is_default: attr_parse(e, "isDefaultVariant").unwrap_or(true),
148            description: child_text(e, "description")?,
149            deprecated: child_text(e, "deprecated")
150                .map(|s| s.parse().unwrap_or(false))
151                .unwrap_or(false),
152            rte_addition: child_text(e, "RTE_components_h").unwrap_or_default(),
153            files,
154        })
155    }
156}
157
158#[derive(Debug, Serialize)]
159pub struct Bundle {
160    name: String,
161    class: String,
162    version: String,
163    vendor: Option<String>,
164    description: String,
165    doc: String,
166    components: Vec<ComponentBuilder>,
167}
168
169impl Bundle {
170    pub fn into_components(self) -> Vec<ComponentBuilder> {
171        let class = self.class;
172        let version = self.version;
173        let vendor = self.vendor;
174        if self.components.is_empty() {
175            log::warn!("Bundle should not be empty")
176        }
177        self.components
178            .into_iter()
179            .map(|comp| ComponentBuilder {
180                class: comp.class.or_else(|| Some(class.clone())),
181                version: comp.version.or_else(|| Some(version.clone())),
182                vendor: comp.vendor.or_else(|| vendor.clone()),
183                ..comp
184            })
185            .collect()
186    }
187}
188
189impl FromElem for Bundle {
190    fn from_elem(e: &Node) -> Result<Self, Error> {
191        assert_root_name(e, "bundle")?;
192        let name: String = attr_map(e, "Cbundle")?;
193        let class: String = attr_map(e, "Cclass")?;
194        let version: String = attr_map(e, "Cversion")?;
195        // let l = l.new(o!("Bundle" => name.clone(),
196        //                  "Class" => class.clone(),
197        //                  "Version" => version.clone()));
198        let components = e
199            .children()
200            .filter_map(move |chld| {
201                if chld.tag_name().name() == "component" {
202                    ComponentBuilder::from_elem(&chld).ok()
203                } else {
204                    None
205                }
206            })
207            .collect();
208        Ok(Self {
209            name,
210            class,
211            version,
212            vendor: attr_map(e, "Cvendor").ok(),
213            description: child_text(e, "description")?,
214            doc: child_text(e, "doc")?,
215            components,
216        })
217    }
218}
219
220fn child_to_component_iter(e: &Node) -> Result<Box<dyn Iterator<Item = ComponentBuilder>>, Error> {
221    match e.tag_name().name() {
222        "bundle" => {
223            let bundle = Bundle::from_elem(e)?;
224            Ok(Box::new(bundle.into_components().into_iter()))
225        }
226        "component" => {
227            let component = ComponentBuilder::from_elem(e)?;
228            Ok(Box::new(Some(component).into_iter()))
229        }
230        _ => Err(format_err!(
231            "element of name {} is not allowed as a descendant of components ({:?})",
232            e.tag_name().name(),
233            e
234        )),
235    }
236}
237
238#[derive(Default)]
239pub struct ComponentBuilders(pub(crate) Vec<ComponentBuilder>);
240
241impl FromElem for ComponentBuilders {
242    fn from_elem(e: &Node) -> Result<Self, Error> {
243        assert_root_name(e, "components")?;
244        Ok(ComponentBuilders(
245            e.children()
246                .filter(|e| e.is_element())
247                .flat_map(move |c| match child_to_component_iter(&c) {
248                    Ok(iter) => iter,
249                    Err(e) => {
250                        log::error!("when trying to parse component: {}", e);
251                        Box::new(None.into_iter())
252                    }
253                })
254                .collect(),
255        ))
256    }
257}