Skip to main content

cmsis_pdsc_parser/
taxonomy.rs

1//! Contains the types required to represent a [PDSC Taxonomy](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/element_taxonomy.html#element_taxonomy) element
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
6/// Represents the [PDSC taxonomy](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/element_taxonomy.html#element_taxonomy) element
7///
8/// Groups `description` entries that define the component classes and group names used in a pack.
9pub struct Taxonomy {
10    /// Component class and group descriptions (1..*)
11    #[serde(rename = "description", default)]
12    pub descriptions: Vec<TaxonomyDescription>,
13}
14
15#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
16/// Represents a [PDSC taxonomy description](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/element_taxonomy.html#element_taxonomyDescription) entry
17///
18/// Defines a component class or a class-and-group combination used to categorise components.
19pub struct TaxonomyDescription {
20    /// Component class name (e.g. `Device`, `CMSIS`, `Board Support`)
21    #[serde(rename = "Cclass")]
22    pub class: String,
23
24    /// Component group name within the class
25    #[serde(rename = "Cgroup")]
26    pub group: Option<String>,
27
28    /// Path or URL to documentation for this class/group
29    pub doc: Option<String>,
30
31    /// Generator identifier associated with this class/group
32    pub generator: Option<String>,
33
34    /// Publishing permission; default `true`
35    pub public: Option<bool>,
36
37    /// Condition ID that applies to this class/group
38    pub condition: Option<String>,
39
40    /// Human-readable description of the component class or group; empty string if absent
41    #[serde(rename = "#content")]
42    pub content: String,
43}
44
45#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
46/// Predefined component class names per
47/// [CclassType](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/element_taxonomy.html#CclassType)
48pub enum CclassType {
49    Audio,
50    BoardSupport,
51    BoardPart,
52    Compiler,
53    /// "CMSIS"
54    Cmsis,
55    /// "CMSIS Driver"
56    CmsisDriver,
57    Device,
58    DataExchange,
59    ExtensionBoard,
60    FileSystem,
61    Graphics,
62    /// "IoT Client"
63    IotClient,
64    /// "IoT Utility"
65    IotUtility,
66    Network,
67    /// "RTOS"
68    Rtos,
69    Security,
70    /// "USB"
71    Usb,
72    Utility,
73}
74
75impl TryFrom<&str> for CclassType {
76    type Error = ();
77    fn try_from(s: &str) -> Result<Self, Self::Error> {
78        match s {
79            "Audio" => Ok(Self::Audio),
80            "Board Support" => Ok(Self::BoardSupport),
81            "Board Part" => Ok(Self::BoardPart),
82            "Compiler" => Ok(Self::Compiler),
83            "CMSIS" => Ok(Self::Cmsis),
84            "CMSIS Driver" => Ok(Self::CmsisDriver),
85            "Device" => Ok(Self::Device),
86            "Data Exchange" => Ok(Self::DataExchange),
87            "Extension Board" => Ok(Self::ExtensionBoard),
88            "File System" => Ok(Self::FileSystem),
89            "Graphics" => Ok(Self::Graphics),
90            "IoT Client" => Ok(Self::IotClient),
91            "IoT Utility" => Ok(Self::IotUtility),
92            "Network" => Ok(Self::Network),
93            "RTOS" => Ok(Self::Rtos),
94            "Security" => Ok(Self::Security),
95            "USB" => Ok(Self::Usb),
96            "Utility" => Ok(Self::Utility),
97            _ => Err(()),
98        }
99    }
100}
101
102impl TryFrom<String> for CclassType {
103    type Error = ();
104    fn try_from(s: String) -> Result<Self, Self::Error> {
105        Self::try_from(s.as_str())
106    }
107}
108
109#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
110/// Predefined component group names per
111/// [CgroupType](https://open-cmsis-pack.github.io/Open-CMSIS-Pack-Spec/main/html/element_taxonomy.html#CgroupType)
112pub enum CgroupType {
113    /// "CORE"
114    Core,
115    /// "DSP"
116    Dsp,
117    /// "NN Lib"
118    NnLib,
119    /// "RTOS"
120    Rtos,
121    /// "RTOS2"
122    Rtos2,
123    Startup,
124}
125
126impl TryFrom<&str> for CgroupType {
127    type Error = ();
128    fn try_from(s: &str) -> Result<Self, Self::Error> {
129        match s {
130            "CORE" => Ok(Self::Core),
131            "DSP" => Ok(Self::Dsp),
132            "NN Lib" => Ok(Self::NnLib),
133            "RTOS" => Ok(Self::Rtos),
134            "RTOS2" => Ok(Self::Rtos2),
135            "Startup" => Ok(Self::Startup),
136            _ => Err(()),
137        }
138    }
139}
140
141impl TryFrom<String> for CgroupType {
142    type Error = ();
143    fn try_from(s: String) -> Result<Self, Self::Error> {
144        Self::try_from(s.as_str())
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    use crate::taxonomy::{Taxonomy, TaxonomyDescription};
151
152    #[test]
153    fn parse_taxonomy() {
154        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
155<taxonomy>
156    <description Cclass="Device" Cgroup="Startup" doc="Device/Doc/startup.htm"
157                 generator="MyGen" public="true" condition="MyCondition">ARM Cortex-M device startup</description>
158    <description Cclass="Board Support"/>
159</taxonomy>"#;
160
161        let taxonomy: Taxonomy = serde_roxmltree::from_str(xml_str).unwrap();
162        assert_eq!(taxonomy.descriptions.len(), 2);
163
164        assert_eq!(
165            taxonomy.descriptions[0],
166            TaxonomyDescription {
167                class: "Device".to_string(),
168                group: Some("Startup".to_string()),
169                doc: Some("Device/Doc/startup.htm".to_string()),
170                generator: Some("MyGen".to_string()),
171                public: Some(true),
172                condition: Some("MyCondition".to_string()),
173                content: "ARM Cortex-M device startup".to_string(),
174            }
175        );
176        assert_eq!(
177            taxonomy.descriptions[1],
178            TaxonomyDescription {
179                class: "Board Support".to_string(),
180                group: None,
181                doc: None,
182                generator: None,
183                public: None,
184                condition: None,
185                content: "".to_string(),
186            }
187        );
188    }
189
190    #[test]
191    fn parse_taxonomy_minimal() {
192        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
193<taxonomy>
194    <description Cclass="CMSIS"/>
195</taxonomy>"#;
196
197        let taxonomy: Taxonomy = serde_roxmltree::from_str(xml_str).unwrap();
198        assert_eq!(taxonomy.descriptions.len(), 1);
199
200        let desc = &taxonomy.descriptions[0];
201        assert_eq!(desc.class, "CMSIS");
202        assert_eq!(desc.group, None);
203        assert_eq!(desc.doc, None);
204        assert_eq!(desc.generator, None);
205        assert_eq!(desc.public, None);
206        assert_eq!(desc.content, "");
207    }
208
209    #[test]
210    fn parse_taxonomy_content() {
211        let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
212<taxonomy>
213    <description Cclass="Compiler">ARM Compiler software components</description>
214</taxonomy>"#;
215
216        let taxonomy: Taxonomy = serde_roxmltree::from_str(xml_str).unwrap();
217        let desc = &taxonomy.descriptions[0];
218
219        assert_eq!(desc.class, "Compiler");
220        assert_eq!(desc.group, None);
221        assert_eq!(desc.content, "ARM Compiler software components");
222    }
223
224    #[test]
225    fn cclass_type_try_from() {
226        use crate::taxonomy::CclassType;
227
228        assert_eq!(CclassType::try_from("Audio"), Ok(CclassType::Audio));
229        assert_eq!(CclassType::try_from("CMSIS"), Ok(CclassType::Cmsis));
230        assert_eq!(
231            CclassType::try_from("CMSIS Driver"),
232            Ok(CclassType::CmsisDriver)
233        );
234        assert_eq!(CclassType::try_from("RTOS"), Ok(CclassType::Rtos));
235        assert_eq!(CclassType::try_from("USB"), Ok(CclassType::Usb));
236        assert_eq!(
237            CclassType::try_from("IoT Client"),
238            Ok(CclassType::IotClient)
239        );
240        assert_eq!(CclassType::try_from("Unknown Class"), Err(()));
241
242        let s = "Board Support".to_string();
243        assert_eq!(CclassType::try_from(s), Ok(CclassType::BoardSupport));
244    }
245
246    #[test]
247    fn cgroup_type_try_from() {
248        use crate::taxonomy::CgroupType;
249
250        assert_eq!(CgroupType::try_from("CORE"), Ok(CgroupType::Core));
251        assert_eq!(CgroupType::try_from("DSP"), Ok(CgroupType::Dsp));
252        assert_eq!(CgroupType::try_from("NN Lib"), Ok(CgroupType::NnLib));
253        assert_eq!(CgroupType::try_from("RTOS"), Ok(CgroupType::Rtos));
254        assert_eq!(CgroupType::try_from("RTOS2"), Ok(CgroupType::Rtos2));
255        assert_eq!(CgroupType::try_from("Startup"), Ok(CgroupType::Startup));
256        assert_eq!(CgroupType::try_from("Unknown Group"), Err(()));
257
258        let s = "NN Lib".to_string();
259        assert_eq!(CgroupType::try_from(s), Ok(CgroupType::NnLib));
260    }
261}