Compare commits
	
		
			11 Commits
		
	
	
		
			177fa8e5a7
			...
			353558737f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 353558737f | ||
|  | 5cd09186fa | ||
|  | 8c7926f199 | ||
|  | 890fdb5629 | ||
|  | e783c29c47 | ||
|  | b89a55632b | ||
|  | a067b85ee2 | ||
|  | e4aff84acb | ||
|  | 3e416bedcc | ||
|  | f58d1d0de5 | ||
|  | 58d81c7a87 | 
| @ -1,6 +1,6 @@ | ||||
| [package] | ||||
| name = "yaserde-examples" | ||||
| version = "0.10.0" | ||||
| version = "0.11.1" | ||||
| authors = ["Marc-Antoine Arnaud <maarnaud@media-io.com>"] | ||||
| license = "MIT" | ||||
| edition = "2018" | ||||
| @ -8,4 +8,4 @@ description = "Examples for YaSerDe project" | ||||
| documentation = "https://docs.rs/yaserde" | ||||
| 
 | ||||
| [dependencies] | ||||
| yaserde = {version = "0.10.0", path = "../yaserde", features = ["yaserde_derive"] } | ||||
| yaserde = {version = "0.11.1", path = "../yaserde", features = ["yaserde_derive"] } | ||||
|  | ||||
| @ -10,7 +10,7 @@ use yaserde::*; | ||||
|   namespace = "html: http://www.w3.org/TR/REC-html40" | ||||
| )] | ||||
| struct Workbook { | ||||
|   #[yaserde(rename = "Worksheet")] | ||||
|   #[yaserde(rename = "Worksheet", prefix = "ss")] | ||||
|   worksheet: Worksheet, | ||||
| } | ||||
| 
 | ||||
| @ -23,7 +23,7 @@ struct Workbook { | ||||
|   namespace = "html: http://www.w3.org/TR/REC-html40" | ||||
| )] | ||||
| struct Worksheet { | ||||
|   #[yaserde(rename = "Table")] | ||||
|   #[yaserde(rename = "Table", prefix = "ss")] | ||||
|   table: Table, | ||||
|   #[yaserde(attribute, rename = "Name", prefix = "ss")] | ||||
|   ws_name: String, | ||||
| @ -53,7 +53,7 @@ struct Table { | ||||
|   #[yaserde(attribute, rename = "DefaultRowHeight", prefix = "ss")] | ||||
|   default_column_height: f32, | ||||
| 
 | ||||
|   #[yaserde(rename = "Row")] | ||||
|   #[yaserde(rename = "Row", prefix = "ss")] | ||||
|   rows: Vec<Row>, | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										102
									
								
								examples/src/generic.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								examples/src/generic.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,102 @@ | ||||
| use yaserde::*; | ||||
| 
 | ||||
| #[derive(YaSerialize, YaDeserialize, Debug, Default, Clone, Eq, PartialEq)] | ||||
| pub struct Header {} | ||||
| 
 | ||||
| #[derive(YaSerialize, YaDeserialize, Debug, Default, Clone, Eq, PartialEq)] | ||||
| #[yaserde(
 | ||||
|   rename = "Envelope", | ||||
|   namespace = "s: http://schemas.xmlsoap.org/soap/envelope/", | ||||
|   prefix = "s" | ||||
| )] | ||||
| pub struct SoapEnvelope<BODY> | ||||
| where | ||||
|   BODY: YaSerialize + YaDeserialize + Default, | ||||
| { | ||||
|   #[yaserde(rename = "encodingStyle", prefix = "s", attribute)] | ||||
|   pub encoding_style: String, | ||||
|   #[yaserde(rename = "u", prefix = "xmlns", attribute)] | ||||
|   pub tnsattr: Option<String>, | ||||
|   #[yaserde(rename = "urn", prefix = "xmlns", attribute)] | ||||
|   pub urnattr: Option<String>, | ||||
|   #[yaserde(rename = "xsi", prefix = "xmlns", attribute)] | ||||
|   pub xsiattr: Option<String>, | ||||
|   #[yaserde(rename = "Header", prefix = "s")] | ||||
|   pub header: Option<Header>, | ||||
|   #[yaserde(rename = "Body", prefix = "s")] | ||||
|   pub body: BODY, | ||||
| } | ||||
| 
 | ||||
| #[derive(YaSerialize, YaDeserialize, Debug, Default, Clone, Eq, PartialEq)] | ||||
| #[yaserde(namespace = "u: urn:schemas-upnp-org:service:AVTransport:1")] | ||||
| pub struct SoapPlay { | ||||
|   #[yaserde(rename = "Play", prefix = "u", default)] | ||||
|   pub body: Play, | ||||
| } | ||||
| 
 | ||||
| #[derive(YaSerialize, YaDeserialize, Debug, Default, Clone, Eq, PartialEq)] | ||||
| #[yaserde(rename = "Play", prefix = "u")] | ||||
| pub struct Play { | ||||
|   #[yaserde(flatten, default)] | ||||
|   pub parameters: Play2, | ||||
| } | ||||
| 
 | ||||
| #[derive(YaSerialize, YaDeserialize, Debug, Default, Clone, Eq, PartialEq)] | ||||
| #[yaserde(
 | ||||
|   rename = "Play", | ||||
|   namespace = "u: urn:schemas-upnp-org:service:AVTransport:1", | ||||
|   prefix = "u" | ||||
| )] | ||||
| pub struct Play2 { | ||||
|   #[yaserde(rename = "InstanceID", default)] | ||||
|   pub instance_id: i32, | ||||
|   #[yaserde(rename = "Speed", default)] | ||||
|   pub speed: i32, | ||||
| } | ||||
| 
 | ||||
| #[derive(PrimitiveYaSerde, Debug, Default, Eq, PartialEq)] | ||||
| struct Meters(i32); | ||||
| 
 | ||||
| #[test] | ||||
| fn test_for_generic_newtype() { | ||||
|   let a = SoapEnvelope { | ||||
|     encoding_style: "".to_string(), | ||||
|     tnsattr: None, | ||||
|     urnattr: None, | ||||
|     xsiattr: None, | ||||
|     header: None, | ||||
|     body: Meters(10), | ||||
|   }; | ||||
| 
 | ||||
|   let s = ser::to_string(&a).unwrap(); | ||||
|   let b: SoapEnvelope<Meters> = de::from_str(&s).unwrap(); | ||||
| 
 | ||||
|   assert_eq!(a, b); | ||||
|   println!("{:#?}", b); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn test_for_generic_nested_struct() { | ||||
|   let a = SoapEnvelope { | ||||
|     encoding_style: "".to_string(), | ||||
|     tnsattr: None, | ||||
|     urnattr: None, | ||||
|     xsiattr: None, | ||||
|     header: None, | ||||
|     body: SoapPlay { | ||||
|       body: Play { | ||||
|         parameters: Play2 { | ||||
|           instance_id: 20, | ||||
|           speed: 1, | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|   }; | ||||
| 
 | ||||
|   let s = ser::to_string(&a).unwrap(); | ||||
|   println!("{s}"); | ||||
|   let b: SoapEnvelope<SoapPlay> = de::from_str(&s).unwrap(); | ||||
| 
 | ||||
|   assert_eq!(a, b); | ||||
|   println!("{:#?}", b); | ||||
| } | ||||
| @ -1,4 +1,6 @@ | ||||
| mod bbigras_namespace; | ||||
| mod boscop; | ||||
| mod generic; | ||||
| mod ln_dom; | ||||
| mod same_element_different_namespaces; | ||||
| mod svd; | ||||
|  | ||||
							
								
								
									
										37
									
								
								examples/src/same_element_different_namespaces.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								examples/src/same_element_different_namespaces.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| // related to issue https://github.com/media-io/yaserde/issues/186
 | ||||
| use yaserde::*; | ||||
| 
 | ||||
| #[derive(YaDeserialize, Debug, PartialEq)] | ||||
| #[yaserde(
 | ||||
|   namespace = "myns: http://my_namespace_1/", | ||||
|   namespace = "ext: http://my_namespace_2/", | ||||
|   prefix = "myns" | ||||
| )] | ||||
| pub struct ErrorType { | ||||
|   #[yaserde(rename = "reasonCode", prefix = "myns")] | ||||
|   pub reason_code: Option<u16>, | ||||
|   #[yaserde(rename = "reasonCode", prefix = "ext")] | ||||
|   pub ext_reason_code: Option<u16>, | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn same_element_different_namespaces() { | ||||
|   use yaserde::de::from_str; | ||||
| 
 | ||||
|   let content = r#" | ||||
|     <error_type xmlns="http://my_namespace_1/" xmlns:ext="http://my_namespace_2/"> | ||||
|       <reasonCode>12</reasonCode> | ||||
|       <ext:reasonCode>32</ext:reasonCode> | ||||
|     </error_type> | ||||
|   "#;
 | ||||
| 
 | ||||
|   let loaded: ErrorType = from_str(content).unwrap(); | ||||
|   println!("{:?}", loaded); | ||||
| 
 | ||||
|   let reference = ErrorType { | ||||
|     reason_code: Some(12), | ||||
|     ext_reason_code: Some(32), | ||||
|   }; | ||||
| 
 | ||||
|   assert_eq!(loaded, reference); | ||||
| } | ||||
| @ -1,124 +1,123 @@ | ||||
| use yaserde::YaSerialize; | ||||
| 
 | ||||
| #[derive(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(PartialEq, Debug, YaSerialize)] | ||||
| struct Field { | ||||
|   name: String, | ||||
|   #[yaserde(child)] | ||||
|   description: String, | ||||
|   #[yaserde(child)] | ||||
|   bitrange: String, | ||||
|   #[yaserde(child)] | ||||
|   access: String, | ||||
| } | ||||
| 
 | ||||
| #[derive(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(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(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(PartialEq, Debug, YaSerialize)] | ||||
| #[yaserde(rename = "device")] | ||||
| struct Device { | ||||
|   #[yaserde(attribute)] | ||||
|   schemaversion: String, | ||||
|   #[yaserde(attribute)] | ||||
|   xmlns: String, | ||||
|   #[yaserde(attribute)] | ||||
|   xsnonamespaceschemalocation: String, | ||||
|   #[yaserde(child)] | ||||
|   devattributes: DevAttrs, | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn parsing_svd() { | ||||
|   use std::fs; | ||||
|   use yaserde::YaSerialize; | ||||
| 
 | ||||
|   #[derive(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(PartialEq, Debug, YaSerialize)] | ||||
|   struct Field { | ||||
|     name: String, | ||||
|     #[yaserde(child)] | ||||
|     description: String, | ||||
|     #[yaserde(child)] | ||||
|     bitrange: String, | ||||
|     #[yaserde(child)] | ||||
|     access: String, | ||||
|   } | ||||
| 
 | ||||
|   #[derive(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(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(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(PartialEq, Debug, YaSerialize)] | ||||
|   #[yaserde(rename = "device")] | ||||
|   struct Device { | ||||
|     #[yaserde(attribute)] | ||||
|     schemaversion: String, | ||||
|     #[yaserde(attribute)] | ||||
|     xmlns: String, | ||||
|     #[yaserde(attribute)] | ||||
|     xsnonamespaceschemalocation: String, | ||||
|     #[yaserde(child)] | ||||
|     devattributes: DevAttrs, | ||||
|   } | ||||
| 
 | ||||
|   let register = Register { | ||||
|         name: "PRCMD".to_string(), | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| [package] | ||||
| name = "yaserde" | ||||
| version = "0.10.0" | ||||
| version = "0.11.1" | ||||
| authors = ["Marc-Antoine Arnaud <arnaud.marcantoine@gmail.com>"] | ||||
| description = "Serialization and deserialization library" | ||||
| keywords = ["Serialization", "Deserialization", "XML"] | ||||
| @ -12,13 +12,13 @@ readme = "../README.md" | ||||
| edition = "2018" | ||||
| 
 | ||||
| [dependencies] | ||||
| yaserde_derive = { version = "0.10.0", path = "../yaserde_derive", optional = true } | ||||
| yaserde_derive = { version = "0.11.1", path = "../yaserde_derive", optional = true } | ||||
| xml-rs = "0.8.3" | ||||
| log = "0.4" | ||||
| 
 | ||||
| [dev-dependencies] | ||||
| env_logger = "0.11.0" | ||||
| yaserde_derive = { version = "0.10.0", path = "../yaserde_derive" } | ||||
| yaserde_derive = { version = "0.11.1", path = "../yaserde_derive" } | ||||
| 
 | ||||
| [badges] | ||||
| travis-ci = { repository = "media-io/yaserde" } | ||||
|  | ||||
| @ -94,6 +94,7 @@ use std::io::{Read, Write}; | ||||
| use xml::writer::XmlEvent; | ||||
| 
 | ||||
| pub mod de; | ||||
| pub mod primitives; | ||||
| pub mod ser; | ||||
| 
 | ||||
| /// A **data structure** that can be deserialized from any data format supported by YaSerDe.
 | ||||
|  | ||||
							
								
								
									
										51
									
								
								yaserde/src/primitives.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								yaserde/src/primitives.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| use std::{io::Read, io::Write}; | ||||
| 
 | ||||
| use crate::{de, ser}; | ||||
| 
 | ||||
| pub fn serialize_primitives<S, W: Write>( | ||||
|   self_bypass: &S, | ||||
|   default_name: &str, | ||||
|   writer: &mut ser::Serializer<W>, | ||||
|   serialize_function: impl FnOnce(&S) -> String, | ||||
| ) -> Result<(), String> { | ||||
|   let name = writer | ||||
|     .get_start_event_name() | ||||
|     .unwrap_or_else(|| default_name.to_string()); | ||||
| 
 | ||||
|   if !writer.skip_start_end() { | ||||
|     writer | ||||
|       .write(xml::writer::XmlEvent::start_element(name.as_str())) | ||||
|       .map_err(|_e| format!("Start element {name:?} write failed"))?; | ||||
|   } | ||||
| 
 | ||||
|   writer | ||||
|     .write(xml::writer::XmlEvent::characters( | ||||
|       serialize_function(self_bypass).as_str(), | ||||
|     )) | ||||
|     .map_err(|_e| format!("Element value {name:?} write failed"))?; | ||||
| 
 | ||||
|   if !writer.skip_start_end() { | ||||
|     writer | ||||
|       .write(xml::writer::XmlEvent::end_element()) | ||||
|       .map_err(|_e| format!("End element {name:?} write failed"))?; | ||||
|   } | ||||
| 
 | ||||
|   Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub fn deserialize_primitives<S, R: Read>( | ||||
|   reader: &mut de::Deserializer<R>, | ||||
|   deserialize_function: impl FnOnce(&str) -> Result<S, String>, | ||||
| ) -> Result<S, String> { | ||||
|   if let Ok(xml::reader::XmlEvent::StartElement { .. }) = reader.peek() { | ||||
|     reader.next_event()?; | ||||
|   } else { | ||||
|     return Err("Start element not found".to_string()); | ||||
|   } | ||||
| 
 | ||||
|   if let Ok(xml::reader::XmlEvent::Characters(ref text)) = reader.peek() { | ||||
|     deserialize_function(text) | ||||
|   } else { | ||||
|     deserialize_function("") | ||||
|   } | ||||
| } | ||||
| @ -1117,3 +1117,20 @@ fn de_nested_macro_rules() { | ||||
| 
 | ||||
|   float_attrs!(f32); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn de_strict() { | ||||
|   init(); | ||||
| 
 | ||||
|   #[derive(PartialEq, Debug, YaDeserialize)] | ||||
|   pub struct Struct { | ||||
|     id: i32, | ||||
|   } | ||||
|   let xml_content = r#"<?xml version="1.0" encoding="utf-8"?>
 | ||||
|       <Struct> | ||||
|           <id>123</id> | ||||
|           <NonExistentAttrShouldCrash></NonExistentAttrShouldCrash> | ||||
|         </Struct>"#;
 | ||||
|   let load: Result<Struct, String> = from_str(xml_content); | ||||
|   assert!(load.is_err()); | ||||
| } | ||||
|  | ||||
							
								
								
									
										41
									
								
								yaserde/tests/generic.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								yaserde/tests/generic.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| #[macro_use] | ||||
| extern crate yaserde; | ||||
| 
 | ||||
| use yaserde::{YaDeserialize, YaSerialize}; | ||||
| 
 | ||||
| fn init() { | ||||
|   let _ = env_logger::builder().is_test(true).try_init(); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn generic() { | ||||
|   init(); | ||||
| 
 | ||||
|   #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] | ||||
|   #[yaserde(rename = "base")] | ||||
|   pub struct Base<G> | ||||
|   where | ||||
|     G: YaSerialize + YaDeserialize + Default, | ||||
|   { | ||||
|     background: G, | ||||
|   } | ||||
| 
 | ||||
|   #[derive(Debug, Default, PartialEq, YaDeserialize, YaSerialize)] | ||||
|   pub struct Generic { | ||||
|     #[yaserde(attribute)] | ||||
|     color: String, | ||||
|   } | ||||
| 
 | ||||
|   let content = r#"<base><background color="blue" /></base>"#; | ||||
|   let model = Base { | ||||
|     background: Generic { | ||||
|       color: "blue".to_string(), | ||||
|     }, | ||||
|   }; | ||||
| 
 | ||||
|   serialize_and_validate!(model, content); | ||||
| 
 | ||||
|   log::debug!("deserialize_and_validate @ {}:{}", file!(), line!()); | ||||
|   let loaded: Result<Base<Generic>, String> = yaserde::de::from_str(content); | ||||
|   assert_eq!(loaded, Ok(model)); | ||||
| } | ||||
| @ -47,7 +47,7 @@ fn skip_serializing_if_for_struct() { | ||||
|     } | ||||
| 
 | ||||
|     fn check_f32_function(&self, value: &f32) -> bool { | ||||
|       (value - 0.0).abs() < std::f32::EPSILON | ||||
|       (value - 0.0).abs() < f32::EPSILON | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| @ -104,7 +104,7 @@ fn skip_serializing_if_for_struct_attributes() { | ||||
|     } | ||||
| 
 | ||||
|     fn check_f32_function(&self, value: &f32) -> bool { | ||||
|       (value - 0.0).abs() < std::f32::EPSILON | ||||
|       (value - 0.0).abs() < f32::EPSILON | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| [package] | ||||
| name = "yaserde_derive" | ||||
| version = "0.10.0" | ||||
| version = "0.11.1" | ||||
| authors = ["Marc-Antoine Arnaud <arnaud.marcantoine@gmail.com>"] | ||||
| description = "Serialization and deserialization macros" | ||||
| keywords = ["Serialization", "Deserialization"] | ||||
| @ -12,7 +12,7 @@ readme = "../README.md" | ||||
| edition = "2018" | ||||
| 
 | ||||
| [dependencies] | ||||
| heck = "0.4.0" | ||||
| heck = "0.5" | ||||
| syn = { version = "~1.0", features = ["visit", "extra-traits"] } | ||||
| proc-macro2 = "~1.0" | ||||
| quote = "~1.0" | ||||
|  | ||||
| @ -90,6 +90,13 @@ impl YaSerdeField { | ||||
|       }, | ||||
|     ); | ||||
| 
 | ||||
|     let prefix = self | ||||
|       .attributes | ||||
|       .prefix | ||||
|       .clone() | ||||
|       .map(|p| format!("{}_", p.to_upper_camel_case())) | ||||
|       .unwrap_or_default(); | ||||
| 
 | ||||
|     let attribute = self | ||||
|       .attributes | ||||
|       .attribute | ||||
| @ -98,7 +105,8 @@ impl YaSerdeField { | ||||
| 
 | ||||
|     Ident::new( | ||||
|       &format!( | ||||
|         "__Visitor_{attribute}{}_{}", | ||||
|         "__Visitor_{attribute}{}{}_{}", | ||||
|         prefix, | ||||
|         label.replace('.', "_").to_upper_camel_case(), | ||||
|         struct_id | ||||
|       ), | ||||
| @ -130,6 +138,20 @@ impl YaSerdeField { | ||||
|       .map(|skip_serializing_if| Ident::new(skip_serializing_if, self.get_span())) | ||||
|   } | ||||
| 
 | ||||
|   pub fn prefix_namespace(&self, root_attributes: &YaSerdeAttribute) -> String { | ||||
|     root_attributes | ||||
|       .namespaces | ||||
|       .iter() | ||||
|       .find_map(|(prefix, namespace)| { | ||||
|         if self.attributes.prefix.eq(prefix) { | ||||
|           Some(namespace.clone()) | ||||
|         } else { | ||||
|           None | ||||
|         } | ||||
|       }) | ||||
|       .unwrap_or_default() | ||||
|   } | ||||
| 
 | ||||
|   pub fn get_namespace_matching( | ||||
|     &self, | ||||
|     root_attributes: &YaSerdeAttribute, | ||||
| @ -261,7 +283,7 @@ impl From<&syn::PathSegment> for Field { | ||||
|           return Field::from(&path.path); | ||||
|         } | ||||
|         Some(syn::GenericArgument::Type(syn::Type::Group(syn::TypeGroup { elem, .. }))) => { | ||||
|           if let syn::Type::Path(ref group) = elem.as_ref() { | ||||
|           if let Path(ref group) = elem.as_ref() { | ||||
|             return Field::from(&group.path); | ||||
|           } | ||||
|         } | ||||
|  | ||||
| @ -1,13 +1,14 @@ | ||||
| use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; | ||||
| use proc_macro2::{Span, TokenStream}; | ||||
| use quote::quote; | ||||
| use syn::{DataEnum, Fields, Ident}; | ||||
| use syn::{DataEnum, Fields, Generics, Ident}; | ||||
| 
 | ||||
| pub fn parse( | ||||
|   data_enum: &DataEnum, | ||||
|   name: &Ident, | ||||
|   root: &str, | ||||
|   root_attributes: &YaSerdeAttribute, | ||||
|   generics: &Generics, | ||||
| ) -> TokenStream { | ||||
|   let namespaces_matching = root_attributes.get_namespace_matching( | ||||
|     &None, | ||||
| @ -23,6 +24,7 @@ pub fn parse( | ||||
|     .collect(); | ||||
| 
 | ||||
|   let flatten = root_attributes.flatten; | ||||
|   let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); | ||||
| 
 | ||||
|   let element_name = if let Some(tag) = &root_attributes.tag { | ||||
|     quote! { | ||||
| @ -39,7 +41,7 @@ pub fn parse( | ||||
|   }; | ||||
| 
 | ||||
|   quote! { | ||||
|     impl ::yaserde::YaDeserialize for #name { | ||||
|     impl #impl_generics ::yaserde::YaDeserialize for #name #ty_generics #where_clause { | ||||
|       #[allow(unused_variables)] | ||||
|       fn deserialize<R: ::std::io::Read>( | ||||
|         reader: &mut ::yaserde::de::Deserializer<R>, | ||||
|  | ||||
| @ -2,13 +2,15 @@ use super::build_default_value::{build_default_value, build_default_vec_value}; | ||||
| use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; | ||||
| use proc_macro2::{Span, TokenStream}; | ||||
| use quote::quote; | ||||
| use syn::{DataStruct, Ident}; | ||||
| use syn::{DataStruct, Generics, Ident}; | ||||
| 
 | ||||
| pub fn parse( | ||||
|   data_struct: &DataStruct, | ||||
|   name: &Ident, | ||||
|   root_namespace: &str, | ||||
|   root: &str, | ||||
|   root_attributes: &YaSerdeAttribute, | ||||
|   generics: &Generics, | ||||
| ) -> TokenStream { | ||||
|   let namespaces_matching = root_attributes.get_namespace_matching( | ||||
|     &None, | ||||
| @ -49,6 +51,17 @@ pub fn parse( | ||||
|     .fields | ||||
|     .iter() | ||||
|     .map(|field| YaSerdeField::new(field.clone())) | ||||
|     .filter(|field| { | ||||
|       if field.is_attribute() { | ||||
|         return true; | ||||
|       }; | ||||
|       match field.get_type() { | ||||
|         Field::FieldVec { data_type } => !matches!(*data_type, Field::FieldStruct { .. }), | ||||
|         Field::FieldOption { data_type } => !matches!(*data_type, Field::FieldStruct { .. }), | ||||
|         Field::FieldStruct { .. } => false, | ||||
|         _ => true, | ||||
|       } | ||||
|     }) | ||||
|     .filter_map(|field| { | ||||
|       let struct_visitor = |struct_name: syn::Path| { | ||||
|         let struct_id: String = struct_name | ||||
| @ -136,9 +149,11 @@ pub fn parse( | ||||
|       let value_label = field.get_value_label(); | ||||
|       let label_name = field.renamed_label_without_namespace(); | ||||
| 
 | ||||
|       let namespace = field.prefix_namespace(root_attributes); | ||||
| 
 | ||||
|       let visit_struct = |struct_name: syn::Path, action: TokenStream| { | ||||
|         Some(quote! { | ||||
|           #label_name => { | ||||
|           (#namespace, #label_name) => { | ||||
|             if depth == 0 { | ||||
|               // Don't count current struct's StartElement as substruct's StartElement
 | ||||
|               let _root = reader.next_event(); | ||||
| @ -369,9 +384,10 @@ pub fn parse( | ||||
|   }; | ||||
| 
 | ||||
|   let flatten = root_attributes.flatten; | ||||
|   let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); | ||||
| 
 | ||||
|   quote! { | ||||
|     impl ::yaserde::YaDeserialize for #name { | ||||
|     impl #impl_generics ::yaserde::YaDeserialize for #name #ty_generics #where_clause { | ||||
|       #[allow(unused_variables)] | ||||
|       fn deserialize<R: ::std::io::Read>( | ||||
|         reader: &mut ::yaserde::de::Deserializer<R>, | ||||
| @ -404,15 +420,20 @@ pub fn parse( | ||||
|           ); | ||||
|           match event { | ||||
|             ::yaserde::__xml::reader::XmlEvent::StartElement{ref name, ref attributes, ..} => { | ||||
|               if depth == 0 && name.local_name == #root { | ||||
|               let namespace = name.namespace.clone().unwrap_or_default(); | ||||
|               if depth == 0 && name.local_name == #root && namespace.as_str() == #root_namespace { | ||||
|                 // Consume root element. We must do this first. In the case it shares a name with a child element, we don't
 | ||||
|                 // want to prematurely match the child element below.
 | ||||
|                 let event = reader.next_event()?; | ||||
|                 #write_unused | ||||
|               } else { | ||||
|                 match name.local_name.as_str() { | ||||
| 
 | ||||
|                 match (namespace.as_str(), name.local_name.as_str()) { | ||||
|                   #call_visitors | ||||
|                   _ => { | ||||
|                     ::yaserde::__derive_trace!("SKIPPINGSKIPPING  Skipping element {:?}", name.local_name); | ||||
|                     return Err(format!("Found unauthorized element {}", name.local_name)); | ||||
| 
 | ||||
|                     let event = reader.next_event()?; | ||||
|                     #write_unused | ||||
| 
 | ||||
| @ -480,8 +501,10 @@ fn build_call_visitor( | ||||
|     quote!(name.local_name.as_str()), | ||||
|   ); | ||||
| 
 | ||||
|   let namespace = field.prefix_namespace(root_attributes); | ||||
| 
 | ||||
|   Some(quote! { | ||||
|     #label_name => { | ||||
|     (#namespace, #label_name) => { | ||||
|       let visitor = #visitor_label{}; | ||||
| 
 | ||||
|       #namespaces_matching | ||||
|  | ||||
| @ -10,21 +10,34 @@ pub fn expand_derive_deserialize(ast: &syn::DeriveInput) -> Result<TokenStream, | ||||
|   let name = &ast.ident; | ||||
|   let attrs = &ast.attrs; | ||||
|   let data = &ast.data; | ||||
|   let generics = &ast.generics; | ||||
| 
 | ||||
|   let root_attributes = YaSerdeAttribute::parse(attrs); | ||||
| 
 | ||||
|   let root_name = format!( | ||||
|     "{}{}", | ||||
|     root_attributes.prefix_namespace(), | ||||
|     root_attributes.xml_element_name(name) | ||||
|   ); | ||||
|   let root_name = root_attributes.xml_element_name(name); | ||||
|   let root_namespace = root_attributes | ||||
|     .namespaces | ||||
|     .iter() | ||||
|     .find_map(|(prefix, namespace)| { | ||||
|       if root_attributes.prefix.eq(prefix) { | ||||
|         Some(namespace.clone()) | ||||
|       } else { | ||||
|         None | ||||
|       } | ||||
|     }) | ||||
|     .unwrap_or_default(); | ||||
| 
 | ||||
|   let impl_block = match *data { | ||||
|     syn::Data::Struct(ref data_struct) => { | ||||
|       expand_struct::parse(data_struct, name, &root_name, &root_attributes) | ||||
|     } | ||||
|     syn::Data::Struct(ref data_struct) => expand_struct::parse( | ||||
|       data_struct, | ||||
|       name, | ||||
|       &root_namespace, | ||||
|       &root_name, | ||||
|       &root_attributes, | ||||
|       generics, | ||||
|     ), | ||||
|     syn::Data::Enum(ref data_enum) => { | ||||
|       expand_enum::parse(data_enum, name, &root_name, &root_attributes) | ||||
|       expand_enum::parse(data_enum, name, &root_name, &root_attributes, generics) | ||||
|     } | ||||
|     syn::Data::Union(ref _data_union) => unimplemented!(), | ||||
|   }; | ||||
|  | ||||
| @ -5,9 +5,13 @@ extern crate proc_macro; | ||||
| 
 | ||||
| mod common; | ||||
| mod de; | ||||
| mod primitives; | ||||
| mod ser; | ||||
| 
 | ||||
| use primitives::{hexbinary_serde, primitive_serde, primitive_yaserde}; | ||||
| use proc_macro::TokenStream; | ||||
| use proc_macro2::TokenStream as TokenStream2; | ||||
| use quote::quote; | ||||
| 
 | ||||
| #[proc_macro_derive(YaDeserialize, attributes(yaserde))] | ||||
| pub fn derive_deserialize(input: TokenStream) -> TokenStream { | ||||
| @ -26,3 +30,37 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream { | ||||
|     Err(msg) => panic!("{}", msg), | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Serialize & Deserialize a struct using it's UpperHex implementation
 | ||||
| #[proc_macro_derive(HexBinaryYaSerde)] | ||||
| pub fn derive_hexbinary(input: TokenStream) -> TokenStream { | ||||
|   let serde: TokenStream2 = hexbinary_serde(input.clone()).into(); | ||||
|   let yaserde: TokenStream2 = primitive_yaserde(input).into(); | ||||
| 
 | ||||
|   quote! { | ||||
|       use ::std::str::FromStr as _; | ||||
|       #serde | ||||
|       #yaserde | ||||
|   } | ||||
|   .into() | ||||
| } | ||||
| 
 | ||||
| // Serialize & Deserialize a primitive newtype by generating a FromStr & Display implementation
 | ||||
| #[proc_macro_derive(PrimitiveYaSerde)] | ||||
| pub fn derive_primitive(input: TokenStream) -> TokenStream { | ||||
|   let serde: TokenStream2 = primitive_serde(input.clone()).into(); | ||||
|   let yaserde: TokenStream2 = primitive_yaserde(input).into(); | ||||
| 
 | ||||
|   quote! { | ||||
|       use ::std::str::FromStr as _; | ||||
|       #serde | ||||
|       #yaserde | ||||
|   } | ||||
|   .into() | ||||
| } | ||||
| 
 | ||||
| // Serialize & Deserialize a type using it's existing FromStr & Display implementation
 | ||||
| #[proc_macro_derive(DefaultYaSerde)] | ||||
| pub fn derive_default(input: TokenStream) -> TokenStream { | ||||
|   primitive_yaserde(input) | ||||
| } | ||||
|  | ||||
							
								
								
									
										118
									
								
								yaserde_derive/src/primitives.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								yaserde_derive/src/primitives.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,118 @@ | ||||
| // Adds YaSerialize and YaDeserialize implementations for types that support FromStr and Display traits.
 | ||||
| // Code originally from `xsd-parser-rs`
 | ||||
| 
 | ||||
| use proc_macro::TokenStream; | ||||
| use proc_macro2::TokenStream as TokenStream2; | ||||
| use quote::quote; | ||||
| use syn::{parse_macro_input, DeriveInput}; | ||||
| 
 | ||||
| pub fn primitive_yaserde(input: TokenStream) -> TokenStream { | ||||
|   let ast = parse_macro_input!(input as DeriveInput); | ||||
| 
 | ||||
|   let struct_name = &ast.ident; | ||||
|   let struct_name_literal = &ast.ident.to_string(); | ||||
| 
 | ||||
|   let serde = quote! { | ||||
|       impl ::yaserde::YaSerialize for #struct_name { | ||||
|           fn serialize<W: ::std::io::Write>( | ||||
|               &self, | ||||
|               writer: &mut ::yaserde::ser::Serializer<W>, | ||||
|           ) -> ::std::result::Result<(), ::std::string::String> { | ||||
|             ::yaserde::primitives::serialize_primitives( | ||||
|                   self, | ||||
|                   #struct_name_literal, | ||||
|                   writer, |s| s.to_string(), | ||||
|               ) | ||||
|           } | ||||
| 
 | ||||
|           fn serialize_attributes( | ||||
|               &self, | ||||
|               attributes: ::std::vec::Vec<::yaserde::__xml::attribute::OwnedAttribute>, | ||||
|               namespace: ::yaserde::__xml::namespace::Namespace, | ||||
|           ) -> ::std::result::Result< | ||||
|               ( | ||||
|                   ::std::vec::Vec<::yaserde::__xml::attribute::OwnedAttribute>, | ||||
|                   ::yaserde::__xml::namespace::Namespace, | ||||
|               ), | ||||
|               ::std::string::String, | ||||
|           > { | ||||
|               Ok((attributes, namespace)) | ||||
|           } | ||||
|       } | ||||
| 
 | ||||
|       impl ::yaserde::YaDeserialize for #struct_name { | ||||
|           fn deserialize<R: ::std::io::Read>( | ||||
|               reader: &mut ::yaserde::de::Deserializer<R>, | ||||
|           ) -> ::std::result::Result<Self, ::std::string::String> { | ||||
|               ::yaserde::primitives::deserialize_primitives( | ||||
|                   reader, | ||||
|                   |s| #struct_name::from_str(s).map_err(|e| e.to_string()), | ||||
|               ) | ||||
|           } | ||||
|       } | ||||
|   }; | ||||
| 
 | ||||
|   serde.into() | ||||
| } | ||||
| 
 | ||||
| pub fn hexbinary_serde(input: TokenStream) -> TokenStream { | ||||
|   let first = input.clone(); | ||||
|   let DeriveInput { ident, .. } = parse_macro_input!(first); | ||||
|   // Calculate number digits to determine whether leading zero should be added
 | ||||
|   quote! { | ||||
|     impl std::fmt::Display for #ident { | ||||
|       fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         write!(f, "{:02X}", self.0) | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     impl ::std::str::FromStr for #ident { | ||||
|       type Err = ::std::string::String; | ||||
| 
 | ||||
|       fn from_str(s: &::std::primitive::str) -> ::std::result::Result<Self, Self::Err> { | ||||
|         Self::from_bits( | ||||
|           s.parse() | ||||
|               .map_err(|_| String::from("Failed to parse Bitflag integer"))?, | ||||
|       ) | ||||
|       .ok_or(String::from("Unknown bits were set in Bitflag")) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .into() | ||||
| } | ||||
| 
 | ||||
| pub fn primitive_serde(input: TokenStream) -> TokenStream { | ||||
|   let first = input.clone(); | ||||
|   let ref di @ DeriveInput { ref ident, .. } = parse_macro_input!(first); | ||||
|   let fromstr = extract_full_path(di).unwrap(); | ||||
|   quote! { | ||||
|     impl std::fmt::Display for #ident { | ||||
|       fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         write!(f, "{}", self.0) | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     impl ::std::str::FromStr for #ident { | ||||
|       type Err = ::std::string::String; | ||||
| 
 | ||||
|       fn from_str(s: &::std::primitive::str) -> ::std::result::Result<Self, Self::Err> { | ||||
|         Ok(#ident(#fromstr)) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .into() | ||||
| } | ||||
| 
 | ||||
| fn extract_full_path(ast: &syn::DeriveInput) -> Result<TokenStream2, syn::Error> { | ||||
|   if let syn::Data::Struct(data_struct) = &ast.data { | ||||
|     if let syn::Fields::Unnamed(fields) = &data_struct.fields { | ||||
|       if let Some(syn::Type::Path(path)) = &fields.unnamed.first().map(|f| &f.ty) { | ||||
|         return Ok( | ||||
|           quote! { <#path as ::std::str::FromStr>::from_str(s).map_err(|e| e.to_string())? }, | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   Err(syn::Error::new_spanned(ast, "Unable to extract full path")) | ||||
| } | ||||
| @ -2,15 +2,16 @@ use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; | ||||
| use crate::ser::{implement_serializer::implement_serializer, label::build_label_name}; | ||||
| use proc_macro2::TokenStream; | ||||
| use quote::quote; | ||||
| use syn::DataEnum; | ||||
| use syn::Fields; | ||||
| use syn::Ident; | ||||
| use syn::{DataEnum, Generics}; | ||||
| 
 | ||||
| pub fn serialize( | ||||
|   data_enum: &DataEnum, | ||||
|   name: &Ident, | ||||
|   root: &str, | ||||
|   root_attributes: &YaSerdeAttribute, | ||||
|   generics: &Generics, | ||||
| ) -> TokenStream { | ||||
|   let inner_enum_inspector = inner_enum_inspector(data_enum, name, root_attributes); | ||||
| 
 | ||||
| @ -108,6 +109,7 @@ pub fn serialize( | ||||
|     quote!(match self { | ||||
|       #inner_enum_inspector | ||||
|     }), | ||||
|     generics, | ||||
|   ) | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -3,14 +3,15 @@ use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; | ||||
| use crate::ser::{element::*, implement_serializer::implement_serializer}; | ||||
| use proc_macro2::TokenStream; | ||||
| use quote::quote; | ||||
| use syn::DataStruct; | ||||
| use syn::Ident; | ||||
| use syn::{DataStruct, Generics}; | ||||
| 
 | ||||
| pub fn serialize( | ||||
|   data_struct: &DataStruct, | ||||
|   name: &Ident, | ||||
|   root: &str, | ||||
|   root_attributes: &YaSerdeAttribute, | ||||
|   generics: &Generics, | ||||
| ) -> TokenStream { | ||||
|   let append_attributes: TokenStream = data_struct | ||||
|     .fields | ||||
| @ -348,5 +349,6 @@ pub fn serialize( | ||||
|     root_attributes, | ||||
|     append_attributes, | ||||
|     struct_inspector, | ||||
|     generics, | ||||
|   ) | ||||
| } | ||||
|  | ||||
| @ -3,6 +3,7 @@ use crate::ser::namespace::generate_namespaces_definition; | ||||
| use proc_macro2::Ident; | ||||
| use proc_macro2::TokenStream; | ||||
| use quote::quote; | ||||
| use syn::Generics; | ||||
| 
 | ||||
| pub fn implement_serializer( | ||||
|   name: &Ident, | ||||
| @ -10,12 +11,15 @@ pub fn implement_serializer( | ||||
|   attributes: &YaSerdeAttribute, | ||||
|   append_attributes: TokenStream, | ||||
|   inner_inspector: TokenStream, | ||||
|   generics: &Generics, | ||||
| ) -> TokenStream { | ||||
|   let namespaces_definition = generate_namespaces_definition(attributes); | ||||
|   let flatten = attributes.flatten; | ||||
| 
 | ||||
|   let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); | ||||
| 
 | ||||
|   quote! { | ||||
|     impl ::yaserde::YaSerialize for #name { | ||||
|     impl #impl_generics ::yaserde::YaSerialize for #name #ty_generics #where_clause { | ||||
|       #[allow(unused_variables)] | ||||
|       fn serialize<W: ::std::io::Write>( | ||||
|         &self, | ||||
|  | ||||
| @ -13,6 +13,7 @@ pub fn expand_derive_serialize(ast: &syn::DeriveInput) -> Result<TokenStream, St | ||||
|   let name = &ast.ident; | ||||
|   let attrs = &ast.attrs; | ||||
|   let data = &ast.data; | ||||
|   let generics = &ast.generics; | ||||
| 
 | ||||
|   let root_attributes = YaSerdeAttribute::parse(attrs); | ||||
| 
 | ||||
| @ -24,10 +25,10 @@ pub fn expand_derive_serialize(ast: &syn::DeriveInput) -> Result<TokenStream, St | ||||
| 
 | ||||
|   let impl_block = match *data { | ||||
|     syn::Data::Struct(ref data_struct) => { | ||||
|       expand_struct::serialize(data_struct, name, &root_name, &root_attributes) | ||||
|       expand_struct::serialize(data_struct, name, &root_name, &root_attributes, generics) | ||||
|     } | ||||
|     syn::Data::Enum(ref data_enum) => { | ||||
|       expand_enum::serialize(data_enum, name, &root_name, &root_attributes) | ||||
|       expand_enum::serialize(data_enum, name, &root_name, &root_attributes, generics) | ||||
|     } | ||||
|     syn::Data::Union(ref _data_union) => unimplemented!(), | ||||
|   }; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user