diff --git a/examples/svd/Cargo.toml b/examples/svd/Cargo.toml new file mode 100644 index 0000000..ae31f81 --- /dev/null +++ b/examples/svd/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "v850-svd" +version = "0.1.0" +authors = ["Roman Valls Guimera "] +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" \ No newline at end of file diff --git a/examples/svd/main.rs b/examples/svd/main.rs new file mode 100644 index 0000000..f988281 --- /dev/null +++ b/examples/svd/main.rs @@ -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 +} + +#[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 +} + +#[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 +} + +#[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 = Vec::new(); + let mut vec_registers: Vec = Vec::new(); + let vec_fields: Vec = 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()); +} \ No newline at end of file diff --git a/yaserde/src/lib.rs b/yaserde/src/lib.rs index 5adce88..005d3a7 100644 --- a/yaserde/src/lib.rs +++ b/yaserde/src/lib.rs @@ -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): +//! +//!``` +//! +//! +//! +//! (...) +//!``` +//! +//! 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;