use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct Parts {
#[serde(rename = "part")]
pub parts: Vec<Part>,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct Part {
#[serde(rename = "Hvendor")]
pub vendor: Option<String>,
#[serde(rename = "Hname")]
pub name: String,
#[serde(rename = "Hclass")]
pub class: Option<String>,
#[serde(rename = "Hgroup")]
pub group: Option<String>,
#[serde(rename = "Hsub")]
pub sub: Option<String>,
#[serde(rename = "Hvariant")]
pub variant: Option<String>,
#[serde(rename = "Hrevision")]
pub revision: Option<String>,
pub description: Option<String>,
#[serde(rename = "feature", default)]
pub features: Vec<Feature>,
#[serde(rename = "book", default)]
pub books: Vec<Book>,
pub image: Option<Image>,
#[serde(rename = "environment", default)]
pub environments: Vec<PartEnvironment>,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct Feature {
#[serde(rename = "Pname")]
pub processor_name: Option<String>,
#[serde(rename = "type")]
pub feature_type: String,
pub n: Option<String>,
pub m: Option<String>,
pub name: Option<String>,
pub count: Option<i32>,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct Book {
#[serde(rename = "Pname")]
pub processor_name: Option<String>,
pub name: String,
pub title: String,
pub public: Option<bool>,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct Image {
pub top: String,
pub bottom: Option<String>,
pub perspective: Option<String>,
pub public: Option<bool>,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct PartEnvironment {
pub name: String,
#[serde(rename = "Pname")]
pub processor_name: Option<String>,
}
#[cfg(test)]
mod tests {
use crate::parts::{Book, Feature, Image, PartEnvironment, Parts};
#[test]
fn parse_parts() {
let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
<parts>
<part Hvendor="Microchip" Hname="ATSAMD21G18A" Hclass="Microcontroller" Hgroup="SAM D21"
Hsub="SAMD21G18A" Hvariant="TQFP48" Hrevision="A">
<description>SAM D21 ARM Cortex-M0+ microcontroller with 256 KB Flash</description>
<feature Pname="Cortex-M0+" type="CoreOther" n="1" name="Cortex-M0+ processor"/>
<feature type="UART" n="6"/>
<book name="docs/SAM_D21_DS.pdf" title="SAM D21 Datasheet" public="true"/>
<image top="images/samd21_top.png" bottom="images/samd21_bottom.png" public="true"/>
</part>
</parts>"#;
let parts: Parts = serde_roxmltree::from_str(xml_str).unwrap();
assert_eq!(parts.parts.len(), 1);
let part = &parts.parts[0];
assert_eq!(part.vendor, Some("Microchip".to_string()));
assert_eq!(part.name, "ATSAMD21G18A");
assert_eq!(part.class, Some("Microcontroller".to_string()));
assert_eq!(part.group, Some("SAM D21".to_string()));
assert_eq!(part.sub, Some("SAMD21G18A".to_string()));
assert_eq!(part.variant, Some("TQFP48".to_string()));
assert_eq!(part.revision, Some("A".to_string()));
assert_eq!(
part.description,
Some("SAM D21 ARM Cortex-M0+ microcontroller with 256 KB Flash".to_string())
);
assert_eq!(
part.features,
vec![
Feature {
processor_name: Some("Cortex-M0+".to_string()),
feature_type: "CoreOther".to_string(),
n: Some("1".to_string()),
m: None,
name: Some("Cortex-M0+ processor".to_string()),
count: None,
},
Feature {
processor_name: None,
feature_type: "UART".to_string(),
n: Some("6".to_string()),
m: None,
name: None,
count: None,
},
]
);
assert_eq!(
part.books,
vec![Book {
processor_name: None,
name: "docs/SAM_D21_DS.pdf".to_string(),
title: "SAM D21 Datasheet".to_string(),
public: Some(true),
}]
);
assert_eq!(
part.image,
Some(Image {
top: "images/samd21_top.png".to_string(),
bottom: Some("images/samd21_bottom.png".to_string()),
perspective: None,
public: Some(true),
})
);
}
#[test]
fn parse_part_minimal() {
let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
<parts>
<part Hname="MY-PART-001"/>
</parts>"#;
let parts: Parts = serde_roxmltree::from_str(xml_str).unwrap();
assert_eq!(parts.parts.len(), 1);
let part = &parts.parts[0];
assert_eq!(part.name, "MY-PART-001");
assert_eq!(part.vendor, None);
assert_eq!(part.class, None);
assert_eq!(part.group, None);
assert_eq!(part.sub, None);
assert_eq!(part.variant, None);
assert_eq!(part.revision, None);
assert_eq!(part.description, None);
assert_eq!(part.features, vec![]);
assert_eq!(part.books, vec![]);
assert_eq!(part.image, None);
}
#[test]
fn parse_parts_multiple() {
let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
<parts>
<part Hvendor="ARM" Hname="CM4-CORE">
<feature type="CoreOther" n="1"/>
</part>
<part Hvendor="ARM" Hname="CM0-CORE" Hrevision="r0p1">
<book name="docs/cm0.pdf" title="Cortex-M0 Technical Reference Manual"/>
</part>
</parts>"#;
let parts: Parts = serde_roxmltree::from_str(xml_str).unwrap();
assert_eq!(parts.parts.len(), 2);
assert_eq!(parts.parts[0].vendor, Some("ARM".to_string()));
assert_eq!(parts.parts[0].name, "CM4-CORE");
assert_eq!(parts.parts[0].features.len(), 1);
assert_eq!(parts.parts[0].books, vec![]);
assert_eq!(parts.parts[1].vendor, Some("ARM".to_string()));
assert_eq!(parts.parts[1].name, "CM0-CORE");
assert_eq!(parts.parts[1].revision, Some("r0p1".to_string()));
assert_eq!(parts.parts[1].features, vec![]);
assert_eq!(parts.parts[1].books.len(), 1);
assert_eq!(parts.parts[1].books[0].name, "docs/cm0.pdf");
assert_eq!(
parts.parts[1].books[0].title,
"Cortex-M0 Technical Reference Manual"
);
}
#[test]
fn parse_part_environments() {
let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
<parts>
<part Hname="MY-CHIP-001">
<environment name="uvision"/>
<environment name="iar" Pname="Core0"/>
</part>
</parts>"#;
let parts: Parts = serde_roxmltree::from_str(xml_str).unwrap();
assert_eq!(parts.parts.len(), 1);
let part = &parts.parts[0];
assert_eq!(part.name, "MY-CHIP-001");
assert_eq!(part.environments.len(), 2);
assert_eq!(
part.environments[0],
PartEnvironment {
name: "uvision".to_string(),
processor_name: None,
}
);
assert_eq!(
part.environments[1],
PartEnvironment {
name: "iar".to_string(),
processor_name: Some("Core0".to_string()),
}
);
}
}