From 9f2cc7575beed04062028a177ca52c8a518da7ed Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Sat, 25 May 2024 20:05:47 +0200 Subject: [PATCH 1/5] Added example for custom serializer based on YaSerialize trait --- examples/Cargo.toml | 1 + examples/src/custom_serializer_ab.rs | 195 +++++++++++++++++++++++++++ examples/src/lib.rs | 1 + examples/tests/data/ab.xml | 18 +++ 4 files changed, 215 insertions(+) create mode 100644 examples/src/custom_serializer_ab.rs create mode 100644 examples/tests/data/ab.xml diff --git a/examples/Cargo.toml b/examples/Cargo.toml index f4e1fc0..051cbcf 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -8,4 +8,5 @@ description = "Examples for YaSerDe project" documentation = "https://docs.rs/yaserde" [dependencies] +xml = "0.8.20" yaserde = {version = "0.10.0", path = "../yaserde", features = ["yaserde_derive"] } diff --git a/examples/src/custom_serializer_ab.rs b/examples/src/custom_serializer_ab.rs new file mode 100644 index 0000000..dabc507 --- /dev/null +++ b/examples/src/custom_serializer_ab.rs @@ -0,0 +1,195 @@ +use yaserde::{YaDeserialize, YaSerialize}; + +#[derive(Debug, YaDeserialize)] +struct RootElem { + #[yaserde()] + children: Vec, + // children are filtered by A and B + // this is usually not desired + #[yaserde()] + a_children: Vec, + #[yaserde()] + b_children: Vec, +} +impl YaSerialize for RootElem { + fn serialize( + &self, + writer: &mut yaserde::ser::Serializer, + ) -> Result<(), String> { + writer.write("Root {\n").unwrap(); + for e in &self.children { + e.serialize(writer).unwrap(); + } + writer.write("/* only A elements */\n").unwrap(); + for e in &self.a_children { + e.serialize(writer).unwrap(); + } + writer.write("/* only B elements */\n").unwrap(); + for e in &self.b_children { + e.serialize(writer).unwrap(); + } + writer.write("}\n").unwrap(); + Ok(()) + } + + fn serialize_attributes( + &self, + attributes: Vec, + namespace: xml::namespace::Namespace, + ) -> Result< + ( + Vec, + xml::namespace::Namespace, + ), + String, + > { + Ok((attributes, namespace)) + } +} + +#[derive(Debug, YaDeserialize)] +struct A { + #[yaserde(attribute)] + attr: String, +} +impl YaSerialize for A { + fn serialize( + &self, + writer: &mut yaserde::ser::Serializer, + ) -> Result<(), String> { + writer.write("A {").unwrap(); + writer + .write(format!("attr: {:?},", self.attr.as_str()).as_str()) + .unwrap(); + writer.write("}\n").unwrap(); + Ok(()) + } + + fn serialize_attributes( + &self, + attributes: Vec, + namespace: xml::namespace::Namespace, + ) -> Result< + ( + Vec, + xml::namespace::Namespace, + ), + String, + > { + Ok((attributes, namespace)) + } +} + +#[derive(Debug, YaDeserialize)] +struct B {} +impl YaSerialize for B { + fn serialize( + &self, + writer: &mut yaserde::ser::Serializer, + ) -> Result<(), String> { + writer.write("B {}\n").unwrap(); + Ok(()) + } + + fn serialize_attributes( + &self, + attributes: Vec, + namespace: xml::namespace::Namespace, + ) -> Result< + ( + Vec, + xml::namespace::Namespace, + ), + String, + > { + Ok((attributes, namespace)) + } +} + +#[derive(Debug, Default, YaDeserialize)] +enum AB { + #[default] + None, + A(A), + B(B), +} + +impl YaSerialize for AB { + fn serialize( + &self, + writer: &mut yaserde::ser::Serializer, + ) -> Result<(), String> { + writer.write("/* serialized AB */\n").unwrap(); + match self { + Self::None => (), + Self::A(_a) => { + writer.write("A {").unwrap(); + } + Self::B(_b) => { + writer.write("B {").unwrap(); + } + } + writer.write("}\n").unwrap(); + Ok(()) + } + + fn serialize_attributes( + &self, + attributes: Vec, + namespace: xml::namespace::Namespace, + ) -> Result< + ( + Vec, + xml::namespace::Namespace, + ), + String, + > { + Ok((attributes, namespace)) + } +} + +#[test] +fn serialize_ab() { + use std::fs; + + let content = + fs::read_to_string("tests/data/ab.xml").expect("something went wrong reading the file"); + let loaded: RootElem = yaserde::de::from_str(&content).unwrap(); + println!("{:?}", &loaded); + let yaserde_conf = yaserde::ser::Config { + indent_string: Some(String::from(" ")), + perform_indent: true, + write_document_declaration: false, + }; + let result = yaserde::ser::to_string_with_config(&loaded, &yaserde_conf).unwrap(); + println!("\n\nSerialized output:\n{:?}", &result); + assert_eq!( + result, + r##"Root { +A{} +B{} +A{} +B{} +A{} +B{} +B{} +B{} +B{} +A{} +B{} +/* only A elements */ +A{} +A{} +A{} +A{} +/* only B elements */ +B{} +B{} +B{} +B{} +B{} +B{} +B{} +}"##, + ) +} diff --git a/examples/src/lib.rs b/examples/src/lib.rs index 439aac9..14a96af 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -1,4 +1,5 @@ mod bbigras_namespace; mod boscop; +mod custom_serializer_ab; mod ln_dom; mod svd; diff --git a/examples/tests/data/ab.xml b/examples/tests/data/ab.xml new file mode 100644 index 0000000..1757e2b --- /dev/null +++ b/examples/tests/data/ab.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + From 2b6724289a8ae5a75f782c8de60913fbd36c82d0 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Mon, 27 May 2024 19:34:36 +0200 Subject: [PATCH 2/5] Format xml and refine example (deserialization with "rename" attribute looks weird though) --- examples/src/custom_serializer_ab.rs | 23 +++++++++++++---------- examples/tests/data/ab.xml | 22 +++++++++++----------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/examples/src/custom_serializer_ab.rs b/examples/src/custom_serializer_ab.rs index dabc507..0536e67 100644 --- a/examples/src/custom_serializer_ab.rs +++ b/examples/src/custom_serializer_ab.rs @@ -2,13 +2,13 @@ use yaserde::{YaDeserialize, YaSerialize}; #[derive(Debug, YaDeserialize)] struct RootElem { - #[yaserde()] + #[yaserde(child)] children: Vec, // children are filtered by A and B // this is usually not desired - #[yaserde()] + #[yaserde(rename = "A")] a_children: Vec, - #[yaserde()] + #[yaserde(rename = "B")] b_children: Vec, } impl YaSerialize for RootElem { @@ -17,6 +17,7 @@ impl YaSerialize for RootElem { writer: &mut yaserde::ser::Serializer, ) -> Result<(), String> { writer.write("Root {\n").unwrap(); + writer.write("/* A|B elements */\n").unwrap(); for e in &self.children { e.serialize(writer).unwrap(); } @@ -110,10 +111,11 @@ impl YaSerialize for B { enum AB { #[default] None, + #[yaserde(rename = "A")] A(A), + #[yaserde(rename = "B")] B(B), } - impl YaSerialize for AB { fn serialize( &self, @@ -122,11 +124,11 @@ impl YaSerialize for AB { writer.write("/* serialized AB */\n").unwrap(); match self { Self::None => (), - Self::A(_a) => { - writer.write("A {").unwrap(); + Self::A(a) => { + a.serialize(writer).unwrap(); } - Self::B(_b) => { - writer.write("B {").unwrap(); + Self::B(b) => { + b.serialize(writer).unwrap(); } } writer.write("}\n").unwrap(); @@ -164,8 +166,9 @@ fn serialize_ab() { let result = yaserde::ser::to_string_with_config(&loaded, &yaserde_conf).unwrap(); println!("\n\nSerialized output:\n{:?}", &result); assert_eq!( - result, + &result, r##"Root { +/* A|B elements */ A{} B{} A{} @@ -182,7 +185,7 @@ A{} A{} A{} A{} -/* only B elements */ +/* only B elements */ B{} B{} B{} diff --git a/examples/tests/data/ab.xml b/examples/tests/data/ab.xml index 1757e2b..4a785b1 100644 --- a/examples/tests/data/ab.xml +++ b/examples/tests/data/ab.xml @@ -4,15 +4,15 @@ Description: Example serializing mixed A,B elements --> - - - - - - - - - - - + + + + + + + + + + + From 5821b4383821e61d96700dbfbc8676f87fc7e395 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Tue, 28 May 2024 17:37:35 +0200 Subject: [PATCH 3/5] Improve test for custom_serializer_example --- examples/src/custom_serializer_ab.rs | 65 +++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/examples/src/custom_serializer_ab.rs b/examples/src/custom_serializer_ab.rs index 0536e67..6a37fd7 100644 --- a/examples/src/custom_serializer_ab.rs +++ b/examples/src/custom_serializer_ab.rs @@ -1,6 +1,6 @@ use yaserde::{YaDeserialize, YaSerialize}; -#[derive(Debug, YaDeserialize)] +#[derive(Debug, PartialEq, YaDeserialize)] struct RootElem { #[yaserde(child)] children: Vec, @@ -48,7 +48,7 @@ impl YaSerialize for RootElem { } } -#[derive(Debug, YaDeserialize)] +#[derive(Debug, PartialEq, YaDeserialize)] struct A { #[yaserde(attribute)] attr: String, @@ -81,7 +81,7 @@ impl YaSerialize for A { } } -#[derive(Debug, YaDeserialize)] +#[derive(Debug, PartialEq, YaDeserialize)] struct B {} impl YaSerialize for B { fn serialize( @@ -107,7 +107,7 @@ impl YaSerialize for B { } } -#[derive(Debug, Default, YaDeserialize)] +#[derive(Debug, Default, PartialEq, YaDeserialize)] enum AB { #[default] None, @@ -165,26 +165,67 @@ fn serialize_ab() { }; let result = yaserde::ser::to_string_with_config(&loaded, &yaserde_conf).unwrap(); println!("\n\nSerialized output:\n{:?}", &result); + + let reference = RootElem { + children: vec![ + AB::A(A { + attr: "hallo 1".to_string(), + }), + AB::B(B {}), + AB::A(A { + attr: "hallo 2".to_string(), + }), + AB::B(B {}), + AB::A(A { + attr: "hallo 3".to_string(), + }), + AB::B(B {}), + AB::B(B {}), + AB::B(B {}), + AB::B(B {}), + AB::A(A { + attr: "hallo 4".to_string(), + }), + AB::B(B {}), + ], + a_children: vec![ + A { + attr: "hallo 1".to_string(), + }, + A { + attr: "hallo 2".to_string(), + }, + A { + attr: "hallo 3".to_string(), + }, + A { + attr: "hallo 4".to_string(), + }, + ], + b_children: vec![B {}, B {}, B {}, B {}, B {}, B {}, B {}], + }; + assert_eq!(&loaded, &reference); + assert_eq!( &result, r##"Root { /* A|B elements */ -A{} +A{attr = "hallo 1"} B{} -A{} +A{attr = "hallo 2"} B{} -A{} +A{attr = "hallo 3"} B{} B{} B{} B{} -A{} +A{attr = "hallo 4"} B{} /* only A elements */ -A{} -A{} -A{} -A{} +A{attr = "hallo 1"} +A{attr = "hallo 2"} +A{attr = "hallo 3"} +A{attr = "hallo 4"} /* only B elements */ B{} B{} From f5b8cf7adf1865312e584f3add7dd2517483f2a2 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Fri, 14 Jun 2024 13:09:26 +0200 Subject: [PATCH 4/5] Update AB example using a custom deserializer for dispatching --- examples/src/custom_serializer_ab.rs | 108 ++++++++++++++++----------- examples/tests/data/ab.xml | 22 +++--- 2 files changed, 76 insertions(+), 54 deletions(-) diff --git a/examples/src/custom_serializer_ab.rs b/examples/src/custom_serializer_ab.rs index 6a37fd7..3483577 100644 --- a/examples/src/custom_serializer_ab.rs +++ b/examples/src/custom_serializer_ab.rs @@ -2,14 +2,7 @@ use yaserde::{YaDeserialize, YaSerialize}; #[derive(Debug, PartialEq, YaDeserialize)] struct RootElem { - #[yaserde(child)] children: Vec, - // children are filtered by A and B - // this is usually not desired - #[yaserde(rename = "A")] - a_children: Vec, - #[yaserde(rename = "B")] - b_children: Vec, } impl YaSerialize for RootElem { fn serialize( @@ -21,14 +14,6 @@ impl YaSerialize for RootElem { for e in &self.children { e.serialize(writer).unwrap(); } - writer.write("/* only A elements */\n").unwrap(); - for e in &self.a_children { - e.serialize(writer).unwrap(); - } - writer.write("/* only B elements */\n").unwrap(); - for e in &self.b_children { - e.serialize(writer).unwrap(); - } writer.write("}\n").unwrap(); Ok(()) } @@ -48,9 +33,11 @@ impl YaSerialize for RootElem { } } -#[derive(Debug, PartialEq, YaDeserialize)] +#[derive(Debug, PartialEq)] +// #[derive(YaDeserialize)] +// #[yaserde(rename = "a")] struct A { - #[yaserde(attribute)] + // #[yaserde(attribute)] attr: String, } impl YaSerialize for A { @@ -81,7 +68,9 @@ impl YaSerialize for A { } } -#[derive(Debug, PartialEq, YaDeserialize)] +#[derive(Debug, PartialEq)] +// #[derive(YaDeserialize)] +// #[yaserde(rename = "b")] struct B {} impl YaSerialize for B { fn serialize( @@ -107,15 +96,44 @@ impl YaSerialize for B { } } -#[derive(Debug, Default, PartialEq, YaDeserialize)] +#[derive(Debug, PartialEq)] +// #[derive(Default)] enum AB { - #[default] - None, - #[yaserde(rename = "A")] + // #[default] + // None, A(A), - #[yaserde(rename = "B")] B(B), } +impl Default for AB { + fn default() -> Self { + // NOTE: for debugging only; will be None + Self::A(A { + attr: String::from("undefined"), + }) + } +} +impl YaDeserialize for AB { + fn deserialize( + reader: &mut yaserde::de::Deserializer, + ) -> Result { + // dispatch to YaDeserialize for element + print!(" - - - - -DISPATCHING"); + if let xml::reader::XmlEvent::StartElement { name, .. } = reader.peek()?.to_owned() { + match name.local_name.as_str() { + "a" => { + let deserialized = A { attr: String::from("NOT DESERIALIZED")}; // TODO: A::deserialize(reader)?; + return Ok(Self::A(deserialized)); + } + "b" => { + let deserialized = B {}; // TODO: B::deserialize(reader)?; + return Ok(Self::B(deserialized)); + } + _ => (), + } + } + Err(format!("Expected a StartElement")) + } +} impl YaSerialize for AB { fn serialize( &self, @@ -123,7 +141,10 @@ impl YaSerialize for AB { ) -> Result<(), String> { writer.write("/* serialized AB */\n").unwrap(); match self { - Self::None => (), + // Self::None => { + // writer.write("UndefinedAB").unwrap(); + // // return Err(format!("None element cannot be serialized")); + // } Self::A(a) => { a.serialize(writer).unwrap(); } @@ -167,42 +188,43 @@ fn serialize_ab() { println!("\n\nSerialized output:\n{:?}", &result); let reference = RootElem { + // ab: AB::default(), children: vec![ AB::A(A { - attr: "hallo 1".to_string(), + attr: String::from("hallo 1"), }), AB::B(B {}), AB::A(A { - attr: "hallo 2".to_string(), + attr: String::from("hallo 2"), }), AB::B(B {}), AB::A(A { - attr: "hallo 3".to_string(), + attr: String::from("hallo 3"), }), AB::B(B {}), AB::B(B {}), AB::B(B {}), AB::B(B {}), AB::A(A { - attr: "hallo 4".to_string(), + attr: String::from("hallo 4"), }), AB::B(B {}), ], - a_children: vec![ - A { - attr: "hallo 1".to_string(), - }, - A { - attr: "hallo 2".to_string(), - }, - A { - attr: "hallo 3".to_string(), - }, - A { - attr: "hallo 4".to_string(), - }, - ], - b_children: vec![B {}, B {}, B {}, B {}, B {}, B {}, B {}], + // a_children: vec![ + // A { + // attr: String::from("hallo 1"), + // }, + // A { + // attr: String::from("hallo 2"), + // }, + // A { + // attr: String::from("hallo 3"), + // }, + // A { + // attr: String::from("hallo 4"), + // }, + // ], + // b_children: vec![B {}, B {}, B {}, B {}, B {}, B {}, B {}], }; assert_eq!(&loaded, &reference); diff --git a/examples/tests/data/ab.xml b/examples/tests/data/ab.xml index 4a785b1..6a26af5 100644 --- a/examples/tests/data/ab.xml +++ b/examples/tests/data/ab.xml @@ -4,15 +4,15 @@ Description: Example serializing mixed A,B elements --> - - - - - - - - - - - + + + + + + + + + + + From 1454fb6292f4c613967cf5784aef087f16e8dd83 Mon Sep 17 00:00:00 2001 From: Nils Fenner Date: Mon, 17 Jun 2024 13:26:16 +0200 Subject: [PATCH 5/5] Ignore the test to allow merging the example at any time --- examples/src/custom_serializer_ab.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/src/custom_serializer_ab.rs b/examples/src/custom_serializer_ab.rs index 3483577..cfebbdd 100644 --- a/examples/src/custom_serializer_ab.rs +++ b/examples/src/custom_serializer_ab.rs @@ -172,6 +172,7 @@ impl YaSerialize for AB { } #[test] +#[ignore = "TODO: fully support Rust enums (allow multiple XML element occurences and create a Vec)"] fn serialize_ab() { use std::fs;