diff --git a/yaserde/src/de/mod.rs b/yaserde/src/de/mod.rs index 227ca0e..68938e1 100644 --- a/yaserde/src/de/mod.rs +++ b/yaserde/src/de/mod.rs @@ -1,3 +1,6 @@ +//! Generic data structure deserialization framework. +//! + use std::io::Read; use xml::name::OwnedName; use xml::reader::{EventReader, ParserConfig, XmlEvent}; diff --git a/yaserde/src/lib.rs b/yaserde/src/lib.rs index 7690ea3..d01ce51 100644 --- a/yaserde/src/lib.rs +++ b/yaserde/src/lib.rs @@ -1,3 +1,8 @@ +//! # YaSerDe +//! +//! YaSerDe is a framework for ***ser***ializing and ***de***serializing Rust data +//! structures efficiently and generically from and into XML. + #[macro_use] extern crate log; extern crate xml; @@ -12,14 +17,17 @@ use xml::writer::XmlEvent; pub mod de; pub mod ser; +/// A **data structure** that can be deserialized from any data format supported by YaSerDe. pub trait YaDeserialize: Sized { fn deserialize(reader: &mut de::Deserializer) -> Result; } +/// A **data structure** that can be serialized into any data format supported by YaSerDe. pub trait YaSerialize: Sized { fn serialize(&self, writer: &mut ser::Serializer) -> Result<(), String>; } +/// A **visitor** that can be implemented to retrieve information from source file. pub trait Visitor<'de>: Sized { /// The value produced by this visitor. type Value; diff --git a/yaserde/src/ser/mod.rs b/yaserde/src/ser/mod.rs index 6886d9a..3366e21 100644 --- a/yaserde/src/ser/mod.rs +++ b/yaserde/src/ser/mod.rs @@ -1,3 +1,6 @@ +//! Generic data structure serialization framework. +//! + use std::io::{Cursor, Write}; use std::str; use xml; diff --git a/yaserde/tests/se_namespace.rs b/yaserde/tests/se_namespace.rs index 201f11e..981307c 100644 --- a/yaserde/tests/se_namespace.rs +++ b/yaserde/tests/se_namespace.rs @@ -161,6 +161,27 @@ fn ser_struct_default_namespace() { convert_and_validate!(model, content); } +#[test] +fn ser_struct_default_namespace_via_attribute() { + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde( + root = "tt", + default_namespace = "ttml", + namespace = "ttml: http://www.w3.org/ns/ttml", + namespace = "ttm: http://www.w3.org/ns/ttml#metadata" + )] + pub struct XmlStruct { + item: String, + } + + let model = XmlStruct { + item: "something".to_string(), + }; + + let content = "something"; + convert_and_validate!(model, content); +} + #[test] fn de_struct_namespace_nested() { #[derive(YaSerialize, Default, PartialEq, Debug)] diff --git a/yaserde_derive/src/attribute.rs b/yaserde_derive/src/attribute.rs index 3caa3ef..f5177a4 100644 --- a/yaserde_derive/src/attribute.rs +++ b/yaserde_derive/src/attribute.rs @@ -6,14 +6,15 @@ use syn::Attribute; #[derive(Debug, PartialEq, Clone)] pub struct YaSerdeAttribute { + pub attribute: bool, + pub default: Option, + pub default_namespace: Option, + pub flatten: bool, + pub namespaces: BTreeMap, + pub prefix: Option, pub root: Option, pub rename: Option, - pub prefix: Option, - pub default: Option, - pub namespaces: BTreeMap, - pub attribute: bool, pub text: bool, - pub flatten: bool, } fn get_value(iter: &mut IntoIter) -> Option { @@ -33,13 +34,14 @@ fn get_value(iter: &mut IntoIter) -> Option { impl YaSerdeAttribute { pub fn parse(attrs: &[Attribute]) -> YaSerdeAttribute { let mut attribute = false; + let mut flatten = false; + let mut default = None; + let mut default_namespace = None; let mut namespaces = BTreeMap::new(); let mut prefix = None; let mut rename = None; let mut root = None; - let mut default = None; let mut text = false; - let mut flatten = false; for attr in attrs.iter() { let mut attr_iter = attr.clone().tokens.into_iter(); @@ -54,6 +56,15 @@ impl YaSerdeAttribute { "attribute" => { attribute = true; } + "default" => { + default = get_value(&mut attr_iter); + } + "default_namespace" => { + default_namespace = get_value(&mut attr_iter); + } + "flatten" => { + flatten = true; + } "namespace" => { if let Some(namespace) = get_value(&mut attr_iter) { let splitted: Vec<&str> = namespace.split(": ").collect(); @@ -74,15 +85,9 @@ impl YaSerdeAttribute { "root" => { root = get_value(&mut attr_iter); } - "default" => { - default = get_value(&mut attr_iter); - } "text" => { text = true; } - "flatten" => { - flatten = true; - } _ => {} } } @@ -94,13 +99,14 @@ impl YaSerdeAttribute { YaSerdeAttribute { attribute, + default, + default_namespace, + flatten, namespaces, prefix, rename, root, - default, text, - flatten, } } } @@ -112,14 +118,15 @@ fn parse_empty_attributes() { assert_eq!( YaSerdeAttribute { + attribute: false, + default: None, + default_namespace: None, + flatten: false, + namespaces: BTreeMap::new(), + prefix: None, root: None, rename: None, - prefix: None, - default: None, - namespaces: BTreeMap::new(), - attribute: false, text: false, - flatten: false, }, attrs ); @@ -160,14 +167,68 @@ fn parse_attributes() { assert_eq!( YaSerdeAttribute { + attribute: true, + default: None, + default_namespace: None, + flatten: false, + namespaces: BTreeMap::new(), + prefix: None, + root: None, + rename: None, + text: false, + }, + attrs + ); +} + +#[test] +fn parse_attributes_with_values() { + use proc_macro2::{Span, TokenStream}; + use std::str::FromStr; + use syn::punctuated::Punctuated; + use syn::token::Bracket; + use syn::token::Pound; + use syn::AttrStyle::Outer; + use syn::{Ident, Path, PathArguments, PathSegment}; + + let mut punctuated = Punctuated::new(); + punctuated.push(PathSegment { + ident: Ident::new("yaserde", Span::call_site()), + arguments: PathArguments::None, + }); + + // #[()] + let attributes = vec![Attribute { + pound_token: Pound { + spans: [Span::call_site()], + }, + style: Outer, + bracket_token: Bracket { + span: Span::call_site(), + }, + path: Path { + leading_colon: None, + segments: punctuated, + }, + tokens: TokenStream::from_str("(attribute, flatten, default_namespace=\"example\", namespace=\"example: http://example.org\")").unwrap(), + }]; + + let attrs = YaSerdeAttribute::parse(&attributes); + + let mut namespaces = BTreeMap::new(); + namespaces.insert("example".to_string(), "http://example.org".to_string()); + + assert_eq!( + YaSerdeAttribute { + attribute: true, + default: None, + default_namespace: Some("example".to_string()), + flatten: true, + namespaces, + prefix: None, root: None, rename: None, - prefix: None, - default: None, - namespaces: BTreeMap::new(), - attribute: true, text: false, - flatten: false, }, attrs ); diff --git a/yaserde_derive/src/ser/expand_enum.rs b/yaserde_derive/src/ser/expand_enum.rs index dadd224..713eba5 100644 --- a/yaserde_derive/src/ser/expand_enum.rs +++ b/yaserde_derive/src/ser/expand_enum.rs @@ -12,6 +12,7 @@ pub fn serialize( name: &Ident, root: &str, namespaces: &BTreeMap, + default_namespace: &Option, ) -> TokenStream { let write_enum_content: TokenStream = data_enum .variants @@ -212,6 +213,13 @@ pub fn serialize( let add_namespaces: TokenStream = namespaces .iter() .map(|(prefix, namespace)| { + if let Some(dn) = default_namespace { + if dn == prefix { + return Some(quote!( + .default_ns(#namespace) + )); + } + } Some(quote!( .ns(#prefix, #namespace) )) diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index 44b872f..6b5b704 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -14,6 +14,7 @@ pub fn serialize( name: &Ident, root: &str, namespaces: &BTreeMap, + default_namespace: &Option, ) -> TokenStream { let build_attributes: TokenStream = data_struct .fields @@ -208,6 +209,13 @@ pub fn serialize( let add_namespaces: TokenStream = namespaces .iter() .map(|(prefix, namespace)| { + if let Some(dn) = default_namespace { + if dn == prefix { + return Some(quote!( + .default_ns(#namespace) + )); + } + } Some(quote!( .ns(#prefix, #namespace) )) diff --git a/yaserde_derive/src/ser/mod.rs b/yaserde_derive/src/ser/mod.rs index ff8ecff..d801b61 100644 --- a/yaserde_derive/src/ser/mod.rs +++ b/yaserde_derive/src/ser/mod.rs @@ -22,12 +22,20 @@ pub fn expand_derive_serialize(ast: &syn::DeriveInput) -> Result { - expand_struct::serialize(data_struct, name, &root, &root_attrs.namespaces) - } - syn::Data::Enum(ref data_enum) => { - expand_enum::serialize(data_enum, name, &root, &root_attrs.namespaces) - } + syn::Data::Struct(ref data_struct) => expand_struct::serialize( + data_struct, + name, + &root, + &root_attrs.namespaces, + &root_attrs.default_namespace, + ), + syn::Data::Enum(ref data_enum) => expand_enum::serialize( + data_enum, + name, + &root, + &root_attrs.namespaces, + &root_attrs.default_namespace, + ), syn::Data::Union(ref _data_union) => unimplemented!(), };