Initial serialize documentation, showcasing XML attributes and children. Left to document or fix are: dependencies and pretty-printing

This commit is contained in:
Roman Valls Guimera 2021-02-08 20:27:16 +11:00
parent e326a978fd
commit d8d84313df
3 changed files with 269 additions and 0 deletions

13
examples/svd/Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "v850-svd"
version = "0.1.0"
authors = ["Roman Valls Guimera <brainstorm@nopcode.org>"]
edition = "2018"
[dependencies]
# serde = { version = "1.0.123", features = [ "derive" ] }
# quick-xml = { version = "0.21.0", features = [ "serialize" ] }
yaserde = "0.5.1"
yaserde_derive = "0.5.1"
xml-rs = "0.8.3"
log = "0.4"

184
examples/svd/main.rs Normal file
View File

@ -0,0 +1,184 @@
use yaserde_derive::YaSerialize;
#[derive(Default, PartialEq, Debug, YaSerialize)]
struct CpuDef {
#[yaserde(child)]
name: String,
#[yaserde(child)]
revision: String,
#[yaserde(child)]
endian: String, // enum {LE, BE, ME}
#[yaserde(child)]
mpupresent: bool,
#[yaserde(child)]
fpupresent: bool,
//#[yaserde(child)]
//nvicpriobits: enum {8, 16, 32, 64, 128},
#[yaserde(child)]
vendorsystickconfig: bool
}
#[derive(Default, PartialEq, Debug, YaSerialize)]
struct Field {
name: String,
#[yaserde(child)]
description: String,
#[yaserde(child)]
bitrange: String,
#[yaserde(child)]
access: String,
}
#[derive(Default, PartialEq, Debug, YaSerialize)]
struct Register {
#[yaserde(child)]
name: String,
#[yaserde(child)]
description: String,
#[yaserde(child)]
addressoffset: String,
#[yaserde(child)]
size: u8,
#[yaserde(child)]
access: String,
#[yaserde(child)]
resetvalue: String,
#[yaserde(child)]
resetmask: String,
#[yaserde(child)]
fields: Vec<Field>
}
#[derive(Default, PartialEq, Debug, YaSerialize)]
struct Peripheral {
#[yaserde(child)]
name: String,
#[yaserde(child)]
version: String,
#[yaserde(child)]
description: String,
#[yaserde(child)]
groupname: String,
#[yaserde(child)]
baseaddress: String,
#[yaserde(child)]
size: u8,
#[yaserde(child)]
access: String,
#[yaserde(child)]
registers: Vec<Register>
}
#[derive(Default, PartialEq, Debug, YaSerialize)]
struct DevAttrs {
#[yaserde(child)]
vendor: String,
#[yaserde(child)]
vendorid: String,
#[yaserde(child)]
name: String,
#[yaserde(child)]
series: String,
#[yaserde(child)]
version: String,
#[yaserde(child)]
description: String,
#[yaserde(child)]
licensetext: String,
#[yaserde(child)]
cpu: CpuDef,
#[yaserde(child)]
addressunitbits: u8,
#[yaserde(child)]
width: u8,
#[yaserde(child)]
size: u8,
#[yaserde(child)]
access: String,
#[yaserde(child)]
resetvalue: String,
#[yaserde(child)]
resetmask: String,
#[yaserde(child)]
peripherals: Vec<Peripheral>
}
#[derive(Default, PartialEq, Debug, YaSerialize)]
#[yaserde(rename = "device")]
struct Device {
#[yaserde(attribute)]
schemaversion: String,
#[yaserde(attribute)]
xmlns: String,
#[yaserde(attribute)]
xsnonamespaceschemalocation: String,
#[yaserde(child)]
devattributes: DevAttrs
}
fn main() {
let mut vec_peripherals: Vec<Peripheral> = Vec::new();
let mut vec_registers: Vec<Register> = Vec::new();
let vec_fields: Vec<Field> = Vec::new();
let register = Register {
name: "PRCMD".to_string(),
description: "This command register (PRCMD) is to protect the registers that may have a significant influence on the application system (PSC, PSM) from an inadvertent write access, so that the system does not stop in case of a program hang-up.".to_string(),
addressoffset: "0xFFFFF1FC".to_string(),
size: 8,
access: "read-write".to_string(),
resetvalue: "0x0000".to_string(),
resetmask: "0xFFFF".to_string(),
fields: vec_fields
};
vec_registers.push(register);
let peripheral = Peripheral {
name: "Specific Registers".to_string(),
version: "1.0".to_string(),
description: "Specific Registers".to_string(),
groupname: "MCU".to_string(),
baseaddress: "0xFFFFF1FC".to_string(),
size: 16,
access: "read-write".to_string(),
registers: vec_registers
};
vec_peripherals.push(peripheral);
let cpu_def = CpuDef {
name: "V850".to_string(),
revision: "r1".to_string(),
endian: "LE".to_string(), // enum {LE, BE, ME}
mpupresent: false,
fpupresent: false,
//nvicpriobits: enum {8, 16, 32, 64, 128},
vendorsystickconfig: false
};
let dev_attrs = DevAttrs {
vendor: "Renesas".to_string(),
vendorid: "Renesas".to_string(),
name: "V850".to_string(),
series: "E1/E2/CA2".to_string(),
version: "1.2".to_string(),
description: "NEC/Renesas V850 automotive grade ICs".to_string(),
licensetext: "GPLv3".to_string(),
cpu: cpu_def,
addressunitbits: 8,
width: 32,
size: 32,
access: "read-write".to_string(),
resetvalue: "0x00000000".to_string(),
resetmask: "0xFFFFFFFF".to_string(),
peripherals: vec_peripherals
};
let dev = Device { schemaversion: "foo".to_string(),
xmlns: "http://www.w3.org/2001/XMLSchema-instance".to_string(),
xsnonamespaceschemalocation: "CMSIS-SVD.xsd".to_string(),
devattributes: dev_attrs
};
println!("{:?}", yaserde::ser::to_string(&dev).ok().unwrap());
}

View File

@ -2,6 +2,78 @@
//!
//! YaSerDe is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically from and into XML.
//!
//! YaSerDe makes it easy to serialize XML documents given an properly annotated struct.
//! Please refer to the `examples` directory for the complete code shown below.
//!
//! # Serialize
//!
//! For instance, let's say that one wants to generate a XML file for the
//! [Rust-Embedded community](https://github.com/rust-embedded/). A well known XML
//! file for microcontrollers is called [SVD](https://github.com/rust-embedded/svd/)
//! and it can be defined on YaSerDe via structs like so:
//!
//!```
//! use yaserde_derive::YaSerialize;
//!
//! #[derive(Default, PartialEq, Debug, YaSerialize)]
//! #[yaserde(rename = "device")]
//! struct Device {
//! #[yaserde(attribute)]
//! schemaversion: String,
//! #[yaserde(attribute)]
//! xmlns: String,
//! #[yaserde(attribute)]
//! xsnonamespaceschemalocation: String,
//! #[yaserde(child)]
//! devattributes: DevAttrs
//! }
//! (...)
//!```
//!
//! The interspersed `#[yaserde()]` macros give some indication of what the resulting XML
//! Will look like, namely, a short snippet of the struct above in XML would be depending on
//! concrete values passed to the struct (not shown):
//!
//!```
//! <device schemaversion: "1.0-example", xmlns: "ns:.... example"
//! xsnonamespaceschemalocation: "foo_bar_baz">
//! <devattributes>
//! </devattributes>
//! (...)
//!```
//!
//! Notice the important difference in **XML output representation between `attributes` vs
//! `child`**, since SVD expects information in that particular arrangement. YaSerDe allows that
//! serialized XML to be valid unlike other Rust XML (de)serialization crates (i.e quick-xml).
//!
//! Also the last `DevAttrs` struct field is indeed another struct, so one can chain several
//! structs to compose the XML structure (again, see examples folder for the complete
//! example).
//!
//! Be mindful that the **Cargo.toml** should not only include `yaserde` and
//! `yaserde_derive`, but also a few necessary dependencies... [FIXME: THAT FOR SOME
//! USER-UNFRIENDLY REASON ARE NOT AUTOMATICALLY PULLED IN AS ONE WOULD EXPECT ;P ;P
//! ... I'm sure there are good reasons, just wanted to leave this like this so that the author
//! can chip in and comment about the reasons behind that decision.](https://github.com/media-io/yaserde/issues/22) ... **I personally think that issue #22 should be reopened and fixed properly (as in only requiring yaserde as a dependency, adding yaserde_derive as a feature).**
//!
//! ```
//! [dependencies]
//! # serde = { version = "1.0.123", features = [ "derive" ] }
//! # quick-xml = { version = "0.21.0", features = [ "serialize" ] }
//! yaserde = "0.5.1"
//! yaserde_derive = "0.5.1"
//! xml-rs = "0.8.3"
//! log = "0.4"
//! ```
//!
//! Last but not least, in order to have a nice, pretty printed XML output one can do
//!
//! ```
//! PLEASE LET THE USERS KNOW HOW TO DO THAT CLEARLY ON YASERDE???
//! ```
//!
//! FIXME: For now I'm just resorting to online XML linters and formatters :_S
#[macro_use]
extern crate log;