Skip to content

Commit

Permalink
Merge 7569408 into 429c2db
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcAntoine-Arnaud committed Jun 7, 2020
2 parents 429c2db + 7569408 commit 11c70db
Show file tree
Hide file tree
Showing 9 changed files with 271 additions and 128 deletions.
30 changes: 28 additions & 2 deletions yaserde/src/lib.rs
Expand Up @@ -23,8 +23,20 @@ pub trait YaDeserialize: Sized {
}

/// A **data structure** that can be serialized into any data format supported by YaSerDe.
pub trait YaSerialize: Sized {
pub trait YaSerialize<'a>: Sized {
fn serialize<W: Write>(&self, writer: &mut ser::Serializer<W>) -> Result<(), String>;

fn serialize_attributes(
&self,
attributes: Vec<xml::attribute::OwnedAttribute>,
namespace: xml::namespace::Namespace,
) -> Result<
(
Vec<xml::attribute::OwnedAttribute>,
xml::namespace::Namespace,
),
String,
>;
}

/// A **visitor** that can be implemented to retrieve information from source file.
Expand Down Expand Up @@ -83,13 +95,27 @@ pub trait Visitor<'de>: Sized {

macro_rules! serialize_type {
($type:ty) => {
impl YaSerialize for $type {
impl<'a> YaSerialize<'a> for $type {
fn serialize<W: Write>(&self, writer: &mut ser::Serializer<W>) -> Result<(), String> {
let content = format!("{}", self);
let event = XmlEvent::characters(&content);
let _ret = writer.write(event);
Ok(())
}

fn serialize_attributes(
&self,
attributes: Vec<xml::attribute::OwnedAttribute>,
namespace: xml::namespace::Namespace,
) -> Result<
(
Vec<xml::attribute::OwnedAttribute>,
xml::namespace::Namespace,
),
String,
> {
Ok((attributes, namespace))
}
}
};
}
Expand Down
13 changes: 8 additions & 5 deletions yaserde/src/ser/mod.rs
Expand Up @@ -7,21 +7,24 @@ use std::str;
use xml::writer::XmlEvent;
use xml::{EmitterConfig, EventWriter};

pub fn to_string<T: YaSerialize>(model: &T) -> Result<String, String> {
pub fn to_string<'a, T: YaSerialize<'a>>(model: &T) -> Result<String, String> {
let buf = Cursor::new(Vec::new());
let cursor = serialize_with_writer(model, buf, &Config::default())?;
let data = str::from_utf8(cursor.get_ref()).expect("Found invalid UTF-8");
Ok(String::from(data))
}

pub fn to_string_with_config<T: YaSerialize>(model: &T, config: &Config) -> Result<String, String> {
pub fn to_string_with_config<'a, T: YaSerialize<'a>>(
model: &T,
config: &Config,
) -> Result<String, String> {
let buf = Cursor::new(Vec::new());
let cursor = serialize_with_writer(model, buf, config)?;
let data = str::from_utf8(cursor.get_ref()).expect("Found invalid UTF-8");
Ok(String::from(data))
}

pub fn serialize_with_writer<W: Write, T: YaSerialize>(
pub fn serialize_with_writer<'a, W: Write, T: YaSerialize<'a>>(
model: &T,
writer: W,
_config: &Config,
Expand All @@ -33,14 +36,14 @@ pub fn serialize_with_writer<W: Write, T: YaSerialize>(
}
}

pub fn to_string_content<T: YaSerialize>(model: &T) -> Result<String, String> {
pub fn to_string_content<'a, T: YaSerialize<'a>>(model: &T) -> Result<String, String> {
let buf = Cursor::new(Vec::new());
let cursor = serialize_with_writer_content(model, buf)?;
let data = str::from_utf8(cursor.get_ref()).expect("Found invalid UTF-8");
Ok(String::from(data))
}

pub fn serialize_with_writer_content<W: Write, T: YaSerialize>(
pub fn serialize_with_writer_content<'a, W: Write, T: YaSerialize<'a>>(
model: &T,
writer: W,
) -> Result<W, String> {
Expand Down
40 changes: 40 additions & 0 deletions yaserde/tests/flatten.rs
Expand Up @@ -144,3 +144,43 @@ fn root_flatten_enum() {
let content = "<Data><string_data>string</string_data></Data>";
serialize_and_validate!(model, content);
}

#[test]
fn flatten_attribute() {
#[derive(Default, PartialEq, Debug, YaDeserialize, YaSerialize)]
struct HtmlText {
#[yaserde(flatten)]
text_attributes: TextAttributes,
#[yaserde(attribute)]
display: String,
}

#[derive(Default, PartialEq, Debug, YaDeserialize, YaSerialize)]
struct TextAttributes {
#[yaserde(attribute)]
bold: bool,
#[yaserde(flatten)]
font: FontAttributes,
}

#[derive(Default, PartialEq, Debug, YaDeserialize, YaSerialize)]
#[yaserde(namespace = "ns: http://www.sample.com/ns/domain")]
pub struct FontAttributes {
#[yaserde(attribute, prefix = "ns")]
size: u32,
}

let model = HtmlText {
text_attributes: TextAttributes {
bold: true,
font: FontAttributes { size: 24 },
},
display: "block".to_string(),
};

let content = r#"
<HtmlText xmlns:ns="http://www.sample.com/ns/domain" display="block" bold="true" ns:size="24" />"#;

serialize_and_validate!(model, content);
deserialize_and_validate!(content, model, HtmlText);
}
16 changes: 15 additions & 1 deletion yaserde/tests/serializer.rs
Expand Up @@ -293,7 +293,7 @@ fn ser_custom() {
value: i32,
}

impl YaSerialize for Day {
impl<'a> YaSerialize<'a> for Day {
fn serialize<W: Write>(&self, writer: &mut yaserde::ser::Serializer<W>) -> Result<(), String> {
let _ret = writer.write(xml::writer::XmlEvent::start_element("DoubleDay"));
let _ret = writer.write(xml::writer::XmlEvent::characters(
Expand All @@ -302,6 +302,20 @@ fn ser_custom() {
let _ret = writer.write(xml::writer::XmlEvent::end_element());
Ok(())
}

fn serialize_attributes(
&self,
attributes: Vec<xml::attribute::OwnedAttribute>,
namespace: xml::namespace::Namespace,
) -> Result<
(
Vec<xml::attribute::OwnedAttribute>,
xml::namespace::Namespace,
),
String,
> {
Ok((attributes, namespace))
}
}

let model = Date {
Expand Down
4 changes: 2 additions & 2 deletions yaserde_derive/src/ser/expand_enum.rs
@@ -1,5 +1,5 @@
use crate::common::{Field, YaSerdeAttribute, YaSerdeField};
use crate::ser::{implement_deserializer::implement_deserializer, label::build_label_name};
use crate::ser::{implement_serializer::implement_serializer, label::build_label_name};
use proc_macro2::TokenStream;
use syn::DataEnum;
use syn::Fields;
Expand All @@ -13,7 +13,7 @@ pub fn serialize(
) -> TokenStream {
let inner_enum_inspector = inner_enum_inspector(data_enum, name, root_attributes);

implement_deserializer(
implement_serializer(
name,
root,
root_attributes,
Expand Down
164 changes: 90 additions & 74 deletions yaserde_derive/src/ser/expand_struct.rs
@@ -1,6 +1,6 @@
use crate::common::{Field, YaSerdeAttribute, YaSerdeField};

use crate::ser::{element::*, implement_deserializer::implement_deserializer};
use crate::ser::{element::*, implement_serializer::implement_serializer};
use proc_macro2::TokenStream;
use syn::DataStruct;
use syn::Ident;
Expand All @@ -11,45 +11,20 @@ pub fn serialize(
root: &str,
root_attributes: &YaSerdeAttribute,
) -> TokenStream {
let build_attributes: TokenStream = data_struct
let append_attributes: TokenStream = data_struct
.fields
.iter()
.map(|field| YaSerdeField::new(field.clone()))
.filter(|field| field.is_attribute())
.filter(|field| field.is_attribute() || field.is_flatten())
.map(|field| {
let label = field.label();
let label_name = field.renamed_label(root_attributes);

match field.get_type() {
Field::FieldString
| Field::FieldBool
| Field::FieldI8
| Field::FieldU8
| Field::FieldI16
| Field::FieldU16
| Field::FieldI32
| Field::FieldU32
| Field::FieldI64
| Field::FieldU64
| Field::FieldF32
| Field::FieldF64 => Some(field.ser_wrap_default_attribute(
Some(quote!(self.#label.to_string())),
quote!({
struct_start_event.attr(#label_name, &yaserde_inner)
}),
)),
Field::FieldOption { data_type } => match *data_type {
Field::FieldString => Some(field.ser_wrap_default_attribute(
None,
quote!({
if let Some(ref value) = self.#label {
struct_start_event.attr(#label_name, value)
} else {
struct_start_event
}
}),
)),
Field::FieldBool
if field.is_attribute() {
let label_name = field.renamed_label(root_attributes);

match field.get_type() {
Field::FieldString
| Field::FieldBool
| Field::FieldI8
| Field::FieldU8
| Field::FieldI16
Expand All @@ -59,55 +34,96 @@ pub fn serialize(
| Field::FieldI64
| Field::FieldU64
| Field::FieldF32
| Field::FieldF64 => Some(field.ser_wrap_default_attribute(
Some(quote!(self.#label.map_or_else(|| String::new(), |v| v.to_string()))),
| Field::FieldF64 => field.ser_wrap_default_attribute(
Some(quote!(self.#label.to_string())),
quote!({
if let Some(ref value) = self.#label {
struct_start_event.attr(#label_name, &yaserde_inner)
} else {
struct_start_event
}
struct_start_event.attr(#label_name, &yaserde_inner)
}),
)),
Field::FieldVec { .. } => {
let item_ident = Ident::new("yaserde_item", field.get_span());
let inner = enclose_formatted_characters(&item_ident, label_name);

Some(field.ser_wrap_default_attribute(
),
Field::FieldOption { data_type } => match *data_type {
Field::FieldString => field.ser_wrap_default_attribute(
None,
quote!({
if let Some(ref yaserde_list) = self.#label {
for yaserde_item in yaserde_list.iter() {
#inner
if let Some(ref value) = self.#label {
struct_start_event.attr(#label_name, value)
} else {
struct_start_event
}
}),
),
Field::FieldBool
| Field::FieldI8
| Field::FieldU8
| Field::FieldI16
| Field::FieldU16
| Field::FieldI32
| Field::FieldU32
| Field::FieldI64
| Field::FieldU64
| Field::FieldF32
| Field::FieldF64 => field.ser_wrap_default_attribute(
Some(quote!(self.#label.map_or_else(|| String::new(), |v| v.to_string()))),
quote!({
if let Some(ref value) = self.#label {
struct_start_event.attr(#label_name, &yaserde_inner)
} else {
struct_start_event
}
}),
),
Field::FieldVec { .. } => {
let item_ident = Ident::new("yaserde_item", field.get_span());
let inner = enclose_formatted_characters(&item_ident, label_name);

field.ser_wrap_default_attribute(
None,
quote!({
if let Some(ref yaserde_list) = self.#label {
for yaserde_item in yaserde_list.iter() {
#inner
}
}
}),
)
}
Field::FieldStruct { .. } => field.ser_wrap_default_attribute(
Some(quote!(self.#label
.as_ref()
.map_or_else(|| Ok(String::new()), |v| yaserde::ser::to_string_content(v))?)),
quote!({
if let Some(ref yaserde_struct) = self.#label {
struct_start_event.attr(#label_name, &yaserde_inner)
} else {
struct_start_event
}
}),
))
}
Field::FieldStruct { .. } => Some(field.ser_wrap_default_attribute(
Some(quote!(self.#label
.as_ref()
.map_or_else(|| Ok(String::new()), |v| yaserde::ser::to_string_content(v))?)),
),
Field::FieldOption { .. } => unimplemented!(),
},
Field::FieldStruct { .. } => field.ser_wrap_default_attribute(
Some(quote!(yaserde::ser::to_string_content(&self.#label)?)),
quote!({
if let Some(ref yaserde_struct) = self.#label {
struct_start_event.attr(#label_name, &yaserde_inner)
} else {
struct_start_event
}
struct_start_event.attr(#label_name, &yaserde_inner)
}),
)),
Field::FieldOption { .. } => unimplemented!(),
},
Field::FieldStruct { .. } => Some(field.ser_wrap_default_attribute(
Some(quote!(yaserde::ser::to_string_content(&self.#label)?)),
quote!({
struct_start_event.attr(#label_name, &yaserde_inner)
}),
)),
Field::FieldVec { .. } => None,
),
Field::FieldVec { .. } => {
// TODO
quote!()
}
}
} else {
match field.get_type() {
Field::FieldStruct { .. } => {
quote!(
let (attributes, namespace) = self.#label.serialize_attributes(vec![], xml::namespace::Namespace::empty())?;
child_attributes_namespace.extend(&namespace);
child_attributes.extend(attributes);
)
}
_ => quote!()
}
}
})
.filter_map(|x| x)
.collect();

let struct_inspector: TokenStream = data_struct
Expand Down Expand Up @@ -267,11 +283,11 @@ pub fn serialize(
.filter_map(|x| x)
.collect();

implement_deserializer(
implement_serializer(
name,
root,
root_attributes,
build_attributes,
append_attributes,
struct_inspector,
)
}

0 comments on commit 11c70db

Please sign in to comment.