1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
6pub struct Parts {
8 #[serde(rename = "part")]
10 pub parts: Vec<Part>,
11}
12
13#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
14pub struct Part {
16 #[serde(rename = "Hvendor")]
18 pub vendor: Option<String>,
19
20 #[serde(rename = "Hname")]
22 pub name: String,
23
24 #[serde(rename = "Hclass")]
26 pub class: Option<String>,
27
28 #[serde(rename = "Hgroup")]
30 pub group: Option<String>,
31
32 #[serde(rename = "Hsub")]
34 pub sub: Option<String>,
35
36 #[serde(rename = "Hvariant")]
38 pub variant: Option<String>,
39
40 #[serde(rename = "Hrevision")]
42 pub revision: Option<String>,
43
44 pub description: Option<String>,
46
47 #[serde(rename = "feature", default)]
49 pub features: Vec<Feature>,
50
51 #[serde(rename = "book", default)]
53 pub books: Vec<Book>,
54
55 pub image: Option<Image>,
57
58 #[serde(rename = "environment", default)]
60 pub environments: Vec<PartEnvironment>,
61}
62
63#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
64pub struct Feature {
66 #[serde(rename = "Pname")]
68 pub processor_name: Option<String>,
69
70 #[serde(rename = "type")]
72 pub feature_type: String,
73
74 pub n: Option<String>,
76
77 pub m: Option<String>,
79
80 pub name: Option<String>,
82
83 pub count: Option<i32>,
85}
86
87#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
88pub struct Book {
90 #[serde(rename = "Pname")]
92 pub processor_name: Option<String>,
93
94 pub name: String,
96
97 pub title: String,
99
100 pub public: Option<bool>,
102}
103
104#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
105pub struct Image {
107 pub top: String,
109
110 pub bottom: Option<String>,
112
113 pub perspective: Option<String>,
115
116 pub public: Option<bool>,
118}
119
120#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
121pub struct PartEnvironment {
123 pub name: String,
125
126 #[serde(rename = "Pname")]
128 pub processor_name: Option<String>,
129}
130
131#[cfg(test)]
132mod tests {
133 use crate::parts::{Book, Feature, Image, PartEnvironment, Parts};
134
135 #[test]
136 fn parse_parts() {
137 let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
138<parts>
139 <part Hvendor="Microchip" Hname="ATSAMD21G18A" Hclass="Microcontroller" Hgroup="SAM D21"
140 Hsub="SAMD21G18A" Hvariant="TQFP48" Hrevision="A">
141 <description>SAM D21 ARM Cortex-M0+ microcontroller with 256 KB Flash</description>
142 <feature Pname="Cortex-M0+" type="CoreOther" n="1" name="Cortex-M0+ processor"/>
143 <feature type="UART" n="6"/>
144 <book name="docs/SAM_D21_DS.pdf" title="SAM D21 Datasheet" public="true"/>
145 <image top="images/samd21_top.png" bottom="images/samd21_bottom.png" public="true"/>
146 </part>
147</parts>"#;
148
149 let parts: Parts = serde_roxmltree::from_str(xml_str).unwrap();
150 assert_eq!(parts.parts.len(), 1);
151
152 let part = &parts.parts[0];
153 assert_eq!(part.vendor, Some("Microchip".to_string()));
154 assert_eq!(part.name, "ATSAMD21G18A");
155 assert_eq!(part.class, Some("Microcontroller".to_string()));
156 assert_eq!(part.group, Some("SAM D21".to_string()));
157 assert_eq!(part.sub, Some("SAMD21G18A".to_string()));
158 assert_eq!(part.variant, Some("TQFP48".to_string()));
159 assert_eq!(part.revision, Some("A".to_string()));
160 assert_eq!(
161 part.description,
162 Some("SAM D21 ARM Cortex-M0+ microcontroller with 256 KB Flash".to_string())
163 );
164 assert_eq!(
165 part.features,
166 vec![
167 Feature {
168 processor_name: Some("Cortex-M0+".to_string()),
169 feature_type: "CoreOther".to_string(),
170 n: Some("1".to_string()),
171 m: None,
172 name: Some("Cortex-M0+ processor".to_string()),
173 count: None,
174 },
175 Feature {
176 processor_name: None,
177 feature_type: "UART".to_string(),
178 n: Some("6".to_string()),
179 m: None,
180 name: None,
181 count: None,
182 },
183 ]
184 );
185 assert_eq!(
186 part.books,
187 vec![Book {
188 processor_name: None,
189 name: "docs/SAM_D21_DS.pdf".to_string(),
190 title: "SAM D21 Datasheet".to_string(),
191 public: Some(true),
192 }]
193 );
194 assert_eq!(
195 part.image,
196 Some(Image {
197 top: "images/samd21_top.png".to_string(),
198 bottom: Some("images/samd21_bottom.png".to_string()),
199 perspective: None,
200 public: Some(true),
201 })
202 );
203 }
204
205 #[test]
206 fn parse_part_minimal() {
207 let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
208<parts>
209 <part Hname="MY-PART-001"/>
210</parts>"#;
211
212 let parts: Parts = serde_roxmltree::from_str(xml_str).unwrap();
213 assert_eq!(parts.parts.len(), 1);
214
215 let part = &parts.parts[0];
216 assert_eq!(part.name, "MY-PART-001");
217 assert_eq!(part.vendor, None);
218 assert_eq!(part.class, None);
219 assert_eq!(part.group, None);
220 assert_eq!(part.sub, None);
221 assert_eq!(part.variant, None);
222 assert_eq!(part.revision, None);
223 assert_eq!(part.description, None);
224 assert_eq!(part.features, vec![]);
225 assert_eq!(part.books, vec![]);
226 assert_eq!(part.image, None);
227 }
228
229 #[test]
230 fn parse_parts_multiple() {
231 let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
232<parts>
233 <part Hvendor="ARM" Hname="CM4-CORE">
234 <feature type="CoreOther" n="1"/>
235 </part>
236 <part Hvendor="ARM" Hname="CM0-CORE" Hrevision="r0p1">
237 <book name="docs/cm0.pdf" title="Cortex-M0 Technical Reference Manual"/>
238 </part>
239</parts>"#;
240
241 let parts: Parts = serde_roxmltree::from_str(xml_str).unwrap();
242 assert_eq!(parts.parts.len(), 2);
243
244 assert_eq!(parts.parts[0].vendor, Some("ARM".to_string()));
245 assert_eq!(parts.parts[0].name, "CM4-CORE");
246 assert_eq!(parts.parts[0].features.len(), 1);
247 assert_eq!(parts.parts[0].books, vec![]);
248
249 assert_eq!(parts.parts[1].vendor, Some("ARM".to_string()));
250 assert_eq!(parts.parts[1].name, "CM0-CORE");
251 assert_eq!(parts.parts[1].revision, Some("r0p1".to_string()));
252 assert_eq!(parts.parts[1].features, vec![]);
253 assert_eq!(parts.parts[1].books.len(), 1);
254 assert_eq!(parts.parts[1].books[0].name, "docs/cm0.pdf");
255 assert_eq!(
256 parts.parts[1].books[0].title,
257 "Cortex-M0 Technical Reference Manual"
258 );
259 }
260
261 #[test]
262 fn parse_part_environments() {
263 let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
264<parts>
265 <part Hname="MY-CHIP-001">
266 <environment name="uvision"/>
267 <environment name="iar" Pname="Core0"/>
268 </part>
269</parts>"#;
270
271 let parts: Parts = serde_roxmltree::from_str(xml_str).unwrap();
272 assert_eq!(parts.parts.len(), 1);
273
274 let part = &parts.parts[0];
275 assert_eq!(part.name, "MY-CHIP-001");
276 assert_eq!(part.environments.len(), 2);
277 assert_eq!(
278 part.environments[0],
279 PartEnvironment {
280 name: "uvision".to_string(),
281 processor_name: None,
282 }
283 );
284 assert_eq!(
285 part.environments[1],
286 PartEnvironment {
287 name: "iar".to_string(),
288 processor_name: Some("Core0".to_string()),
289 }
290 );
291 }
292}