diff --git a/examples/src/generic.rs b/examples/src/generic.rs
new file mode 100644
index 0000000..0358382
--- /dev/null
+++ b/examples/src/generic.rs
@@ -0,0 +1,100 @@
+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
+where
+ BODY: YaSerialize + YaDeserialize + Default,
+{
+ #[yaserde(rename = "encodingStyle", prefix = "s", attribute)]
+ pub encoding_style: String,
+ #[yaserde(rename = "u", prefix = "xmlns", attribute)]
+ pub tnsattr: Option,
+ #[yaserde(rename = "urn", prefix = "xmlns", attribute)]
+ pub urnattr: Option,
+ #[yaserde(rename = "xsi", prefix = "xmlns", attribute)]
+ pub xsiattr: Option,
+ #[yaserde(rename = "Header", prefix = "s")]
+ pub header: Option,
+ #[yaserde(rename = "Body", prefix = "s")]
+ pub body: BODY,
+}
+
+#[derive(YaSerialize, YaDeserialize, Debug, Default, Clone, Eq, PartialEq)]
+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 = 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();
+ let b: SoapEnvelope = de::from_str(&s).unwrap();
+
+ assert_eq!(a, b);
+ println!("{:#?}", b);
+}
diff --git a/examples/src/lib.rs b/examples/src/lib.rs
index 439aac9..8f83b28 100644
--- a/examples/src/lib.rs
+++ b/examples/src/lib.rs
@@ -1,4 +1,5 @@
mod bbigras_namespace;
mod boscop;
+mod generic;
mod ln_dom;
mod svd;
diff --git a/examples/src/svd.rs b/examples/src/svd.rs
index 2a8d72b..f41b8b5 100644
--- a/examples/src/svd.rs
+++ b/examples/src/svd.rs
@@ -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,
-}
-
-#[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,
-}
-
-#[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,
-}
-
-#[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,
+ }
+
+ #[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,
+ }
+
+ #[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,
+ }
+
+ #[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(),
diff --git a/yaserde/src/lib.rs b/yaserde/src/lib.rs
index 971ce48..720782e 100644
--- a/yaserde/src/lib.rs
+++ b/yaserde/src/lib.rs
@@ -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.
diff --git a/yaserde/src/primitives.rs b/yaserde/src/primitives.rs
new file mode 100644
index 0000000..0d4107f
--- /dev/null
+++ b/yaserde/src/primitives.rs
@@ -0,0 +1,51 @@
+use std::{io::Read, io::Write};
+
+use crate::{de, ser};
+
+pub fn serialize_primitives(
+ self_bypass: &S,
+ default_name: &str,
+ writer: &mut ser::Serializer,
+ 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(
+ reader: &mut de::Deserializer,
+ deserialize_function: impl FnOnce(&str) -> Result,
+) -> Result {
+ 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("")
+ }
+}
diff --git a/yaserde/tests/generic.rs b/yaserde/tests/generic.rs
new file mode 100644
index 0000000..5aba46c
--- /dev/null
+++ b/yaserde/tests/generic.rs
@@ -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
+ where
+ G: YaSerialize + YaDeserialize + Default,
+ {
+ background: G,
+ }
+
+ #[derive(Debug, Default, PartialEq, YaDeserialize, YaSerialize)]
+ pub struct Generic {
+ #[yaserde(attribute)]
+ color: String,
+ }
+
+ let content = r#""#;
+ let model = Base {
+ background: Generic {
+ color: "blue".to_string(),
+ },
+ };
+
+ serialize_and_validate!(model, content);
+
+ log::debug!("deserialize_and_validate @ {}:{}", file!(), line!());
+ let loaded: Result, String> = yaserde::de::from_str(content);
+ assert_eq!(loaded, Ok(model));
+}
diff --git a/yaserde_derive/src/de/expand_enum.rs b/yaserde_derive/src/de/expand_enum.rs
index 5a41c57..b025ab9 100644
--- a/yaserde_derive/src/de/expand_enum.rs
+++ b/yaserde_derive/src/de/expand_enum.rs
@@ -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(
reader: &mut ::yaserde::de::Deserializer,
diff --git a/yaserde_derive/src/de/expand_struct.rs b/yaserde_derive/src/de/expand_struct.rs
index 5ca527a..782aa08 100644
--- a/yaserde_derive/src/de/expand_struct.rs
+++ b/yaserde_derive/src/de/expand_struct.rs
@@ -2,13 +2,14 @@ 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: &str,
root_attributes: &YaSerdeAttribute,
+ generics: &Generics,
) -> TokenStream {
let namespaces_matching = root_attributes.get_namespace_matching(
&None,
@@ -49,6 +50,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
@@ -369,9 +381,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(
reader: &mut ::yaserde::de::Deserializer,
diff --git a/yaserde_derive/src/de/mod.rs b/yaserde_derive/src/de/mod.rs
index 043a3a0..31453f7 100644
--- a/yaserde_derive/src/de/mod.rs
+++ b/yaserde_derive/src/de/mod.rs
@@ -10,6 +10,7 @@ pub fn expand_derive_deserialize(ast: &syn::DeriveInput) -> Result Result {
- expand_struct::parse(data_struct, name, &root_name, &root_attributes)
+ expand_struct::parse(data_struct, name, &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!(),
};
diff --git a/yaserde_derive/src/lib.rs b/yaserde_derive/src/lib.rs
index 9d881a1..914cc30 100644
--- a/yaserde_derive/src/lib.rs
+++ b/yaserde_derive/src/lib.rs
@@ -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)
+}
diff --git a/yaserde_derive/src/primitives.rs b/yaserde_derive/src/primitives.rs
new file mode 100644
index 0000000..8847521
--- /dev/null
+++ b/yaserde_derive/src/primitives.rs
@@ -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(
+ &self,
+ writer: &mut ::yaserde::ser::Serializer,
+ ) -> ::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(
+ reader: &mut ::yaserde::de::Deserializer,
+ ) -> ::std::result::Result {
+ ::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::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 {
+ Ok(#ident(#fromstr))
+ }
+ }
+ }
+ .into()
+}
+
+fn extract_full_path(ast: &syn::DeriveInput) -> Result {
+ 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"))
+}
diff --git a/yaserde_derive/src/ser/expand_enum.rs b/yaserde_derive/src/ser/expand_enum.rs
index 3ef0bed..4d13abb 100644
--- a/yaserde_derive/src/ser/expand_enum.rs
+++ b/yaserde_derive/src/ser/expand_enum.rs
@@ -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,
)
}
diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs
index 6bb5c49..b9e836e 100644
--- a/yaserde_derive/src/ser/expand_struct.rs
+++ b/yaserde_derive/src/ser/expand_struct.rs
@@ -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,
)
}
diff --git a/yaserde_derive/src/ser/implement_serializer.rs b/yaserde_derive/src/ser/implement_serializer.rs
index da3d9ab..82c3759 100644
--- a/yaserde_derive/src/ser/implement_serializer.rs
+++ b/yaserde_derive/src/ser/implement_serializer.rs
@@ -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(
&self,
diff --git a/yaserde_derive/src/ser/mod.rs b/yaserde_derive/src/ser/mod.rs
index 98548ab..a09e181 100644
--- a/yaserde_derive/src/ser/mod.rs
+++ b/yaserde_derive/src/ser/mod.rs
@@ -13,6 +13,7 @@ pub fn expand_derive_serialize(ast: &syn::DeriveInput) -> Result Result {
- 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!(),
};