use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct Examples {
#[serde(rename = "example", default)]
pub examples: Vec<Example>,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct Example {
pub name: String,
pub folder: String,
pub archive: Option<String>,
pub doc: String,
pub version: Option<String>,
pub public: Option<bool>,
pub description: String,
#[serde(rename = "board", default)]
pub boards: Vec<ExampleBoard>,
pub project: ExampleProject,
pub attributes: Option<ExampleAttributes>,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct ExampleBoard {
pub vendor: String,
pub name: String,
pub revision: Option<String>,
#[serde(rename = "Dvendor")]
pub device_vendor: Option<String>,
#[serde(rename = "Dname")]
pub device_name: Option<String>,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct ExampleProject {
#[serde(rename = "environment", default)]
pub environments: Vec<ExampleEnvironment>,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct ExampleEnvironment {
pub name: String,
pub load: String,
pub folder: Option<String>,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct ExampleAttributes {
#[serde(rename = "category", default)]
pub categories: Vec<String>,
#[serde(rename = "component", default)]
pub components: Vec<ExampleComponent>,
#[serde(rename = "keyword", default)]
pub keywords: Vec<String>,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
pub struct ExampleComponent {
#[serde(rename = "Cclass")]
pub class: String,
#[serde(rename = "Cgroup")]
pub group: Option<String>,
#[serde(rename = "Csub")]
pub sub: Option<String>,
#[serde(rename = "Cversion")]
pub version: Option<String>,
#[serde(rename = "Cvendor")]
pub vendor: Option<String>,
#[serde(rename = "Cbundle")]
pub bundle: Option<String>,
#[serde(rename = "Cvariant")]
pub variant: Option<String>,
#[serde(rename = "Capiversion")]
pub api_version: Option<String>,
pub instances: Option<u32>,
}
#[cfg(test)]
mod tests {
use crate::examples::{
ExampleBoard, ExampleComponent, ExampleEnvironment, ExampleProject, Examples,
};
#[test]
fn parse_examples() {
let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
<examples>
<example name="Blinky" folder="examples/Blinky" doc="examples/Blinky/README.md"
archive="Blinky.zip" version="1.2.0" public="true">
<description>Blinky LED example for Cortex-M4</description>
<board vendor="STMicroelectronics" name="NUCLEO-F401RE" revision="B"
Dvendor="STMicroelectronics:13" Dname="STM32F401RETx"/>
<project>
<environment name="uv" load="Blinky.uvprojx"/>
<environment name="csolution" load="Blinky.csolution.yml" folder="csolution"/>
</project>
<attributes>
<category>Getting Started</category>
<component Cclass="CMSIS" Cgroup="RTOS2" Cversion="2.0.0" Cvendor="ARM"
Cbundle="ARM" Cvariant="Keil" Capiversion="1.0.0" instances="2"/>
<keyword>LED</keyword>
<keyword>Blinky</keyword>
</attributes>
</example>
<example name="Hello" folder="examples/Hello" doc="examples/Hello/README.md">
<description>Hello World via UART</description>
<project>
<environment name="uv" load="Hello.uvprojx"/>
</project>
</example>
</examples>"#;
let examples: Examples = serde_roxmltree::from_str(xml_str).unwrap();
assert_eq!(examples.examples.len(), 2);
let e0 = &examples.examples[0];
assert_eq!(e0.name, "Blinky");
assert_eq!(e0.folder, "examples/Blinky");
assert_eq!(e0.doc, "examples/Blinky/README.md");
assert_eq!(e0.archive, Some("Blinky.zip".to_string()));
assert_eq!(e0.version, Some("1.2.0".to_string()));
assert_eq!(e0.public, Some(true));
assert_eq!(e0.description, "Blinky LED example for Cortex-M4");
assert_eq!(
e0.boards,
vec![ExampleBoard {
vendor: "STMicroelectronics".to_string(),
name: "NUCLEO-F401RE".to_string(),
revision: Some("B".to_string()),
device_vendor: Some("STMicroelectronics:13".to_string()),
device_name: Some("STM32F401RETx".to_string()),
}]
);
assert_eq!(
e0.project,
ExampleProject {
environments: vec![
ExampleEnvironment {
name: "uv".to_string(),
load: "Blinky.uvprojx".to_string(),
folder: None,
},
ExampleEnvironment {
name: "csolution".to_string(),
load: "Blinky.csolution.yml".to_string(),
folder: Some("csolution".to_string()),
},
],
}
);
let attrs = e0.attributes.as_ref().unwrap();
assert_eq!(attrs.categories, vec!["Getting Started".to_string()]);
assert_eq!(
attrs.components,
vec![ExampleComponent {
class: "CMSIS".to_string(),
group: Some("RTOS2".to_string()),
sub: None,
version: Some("2.0.0".to_string()),
vendor: Some("ARM".to_string()),
bundle: Some("ARM".to_string()),
variant: Some("Keil".to_string()),
api_version: Some("1.0.0".to_string()),
instances: Some(2),
}]
);
assert_eq!(
attrs.keywords,
vec!["LED".to_string(), "Blinky".to_string()]
);
let e1 = &examples.examples[1];
assert_eq!(e1.name, "Hello");
assert_eq!(e1.archive, None);
assert_eq!(e1.version, None);
assert_eq!(e1.boards, vec![]);
assert_eq!(e1.attributes, None);
}
#[test]
fn parse_example_minimal() {
let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
<examples>
<example name="Minimal" folder="examples/Minimal" doc="examples/Minimal/README.md">
<description>Minimal example</description>
<project>
<environment name="uv" load="Minimal.uvprojx"/>
</project>
</example>
</examples>"#;
let examples: Examples = serde_roxmltree::from_str(xml_str).unwrap();
assert_eq!(examples.examples.len(), 1);
let e = &examples.examples[0];
assert_eq!(e.name, "Minimal");
assert_eq!(e.folder, "examples/Minimal");
assert_eq!(e.doc, "examples/Minimal/README.md");
assert_eq!(e.archive, None);
assert_eq!(e.version, None);
assert_eq!(e.public, None);
assert_eq!(e.description, "Minimal example");
assert_eq!(e.boards, vec![]);
assert_eq!(e.project.environments.len(), 1);
assert_eq!(e.project.environments[0].name, "uv");
assert_eq!(e.project.environments[0].load, "Minimal.uvprojx");
assert_eq!(e.project.environments[0].folder, None);
assert_eq!(e.attributes, None);
}
#[test]
fn parse_example_attributes() {
let xml_str = r#"<?xml version="1.0" encoding="UTF-8"?>
<examples>
<example name="Tagged" folder="examples/Tagged" doc="examples/Tagged/README.md">
<description>Example with rich attributes</description>
<project>
<environment name="csolution" load="Tagged.csolution.yml"/>
</project>
<attributes>
<category>Middleware</category>
<category>Networking</category>
<component Cclass="Network" Cgroup="Core" Csub="IPv4" Cversion="7.15.0" Cvendor="Keil"/>
<component Cclass="CMSIS"/>
<keyword>TCP/IP</keyword>
</attributes>
</example>
</examples>"#;
let examples: Examples = serde_roxmltree::from_str(xml_str).unwrap();
let e = &examples.examples[0];
let attrs = e.attributes.as_ref().unwrap();
assert_eq!(
attrs.categories,
vec!["Middleware".to_string(), "Networking".to_string()]
);
assert_eq!(
attrs.components,
vec![
ExampleComponent {
class: "Network".to_string(),
group: Some("Core".to_string()),
sub: Some("IPv4".to_string()),
version: Some("7.15.0".to_string()),
vendor: Some("Keil".to_string()),
bundle: None,
variant: None,
api_version: None,
instances: None,
},
ExampleComponent {
class: "CMSIS".to_string(),
group: None,
sub: None,
version: None,
vendor: None,
bundle: None,
variant: None,
api_version: None,
instances: None,
},
]
);
assert_eq!(attrs.keywords, vec!["TCP/IP".to_string()]);
}
}