yaserde/yaserde_derive/src/ser/expand_struct.rs
2022-01-07 08:39:25 -08:00

337 lines
11 KiB
Rust

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;
pub fn serialize(
data_struct: &DataStruct,
name: &Ident,
root: &str,
root_attributes: &YaSerdeAttribute,
) -> TokenStream {
let append_attributes: TokenStream = data_struct
.fields
.iter()
.map(|field| YaSerdeField::new(field.clone()))
.filter(|field| field.is_attribute() || field.is_flatten())
.map(|field| {
let label = field.label();
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
| Field::FieldU16
| Field::FieldI32
| Field::FieldU32
| Field::FieldI64
| Field::FieldU64
| Field::FieldF32
| Field::FieldF64 => 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 => field.ser_wrap_default_attribute(
None,
quote!({
if let ::std::option::Option::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(|| ::std::string::String::new(), |v| v.to_string())),
),
quote!({
if let ::std::option::Option::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 ::std::option::Option::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(
|| ::std::result::Result::Ok(::std::string::String::new()),
|v| ::yaserde::ser::to_string_content(v),
)?
}),
quote!({
if let ::std::option::Option::Some(ref yaserde_struct) = self.#label {
struct_start_event.attr(#label_name, &yaserde_inner)
} else {
struct_start_event
}
}),
),
Field::FieldOption { .. } => unimplemented!(),
},
Field::FieldStruct { .. } => 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 { .. } => {
// TODO
quote!()
}
}
} else {
match field.get_type() {
Field::FieldStruct { .. } => {
quote!(
let (attributes, namespace) = self.#label.serialize_attributes(
::std::vec![],
::yaserde::__xml::namespace::Namespace::empty(),
)?;
child_attributes_namespace.extend(&namespace);
child_attributes.extend(attributes);
)
}
_ => quote!(),
}
}
})
.collect();
let struct_inspector: TokenStream = data_struct
.fields
.iter()
.map(|field| YaSerdeField::new(field.clone()))
.filter(|field| !field.is_attribute())
.filter_map(|field| {
let label = field.label();
if field.is_text_content() {
return match field.get_type() {
Field::FieldOption { .. } => Some(quote!(
let s = self.#label.as_deref().unwrap_or_default();
let data_event = ::yaserde::__xml::writer::XmlEvent::characters(s);
writer.write(data_event).map_err(|e| e.to_string())?;
)),
_ => Some(quote!(
let data_event = ::yaserde::__xml::writer::XmlEvent::characters(&self.#label);
writer.write(data_event).map_err(|e| e.to_string())?;
)),
};
}
let label_name = field.renamed_label(root_attributes);
let conditions = condition_generator(&label, &field);
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 => serialize_element(&label, label_name, &conditions),
Field::FieldOption { data_type } => match *data_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 => {
let item_ident = Ident::new("yaserde_item", field.get_span());
let inner = enclose_formatted_characters_for_value(&item_ident, label_name);
Some(quote! {
#conditions {
if let Some(ref yaserde_item) = self.#label {
#inner
}
}
})
}
Field::FieldVec { .. } => {
let item_ident = Ident::new("yaserde_item", field.get_span());
let inner = enclose_formatted_characters_for_value(&item_ident, label_name);
Some(quote! {
#conditions {
if let ::std::option::Option::Some(ref yaserde_items) = &self.#label {
for yaserde_item in yaserde_items.iter() {
#inner
}
}
}
})
}
Field::FieldStruct { .. } => Some(if field.is_flatten() {
quote! {
if let ::std::option::Option::Some(ref item) = &self.#label {
writer.set_start_event_name(::std::option::Option::None);
writer.set_skip_start_end(true);
::yaserde::YaSerialize::serialize(item, writer)?;
}
}
} else {
quote! {
if let ::std::option::Option::Some(ref item) = &self.#label {
writer.set_start_event_name(::std::option::Option::Some(#label_name.to_string()));
writer.set_skip_start_end(false);
::yaserde::YaSerialize::serialize(item, writer)?;
}
}
}),
_ => unimplemented!(),
},
Field::FieldStruct { .. } => {
let (start_event, skip_start) = if field.is_flatten() {
(quote!(::std::option::Option::None), true)
} else {
(
quote!(::std::option::Option::Some(#label_name.to_string())),
false,
)
};
Some(quote! {
writer.set_start_event_name(#start_event);
writer.set_skip_start_end(#skip_start);
::yaserde::YaSerialize::serialize(&self.#label, writer)?;
})
}
Field::FieldVec { data_type } => match *data_type {
Field::FieldString => {
let item_ident = Ident::new("yaserde_item", field.get_span());
let inner = enclose_formatted_characters_for_value(&item_ident, label_name);
Some(quote! {
for yaserde_item in &self.#label {
#inner
}
})
}
Field::FieldBool
| Field::FieldI8
| Field::FieldU8
| Field::FieldI16
| Field::FieldU16
| Field::FieldI32
| Field::FieldU32
| Field::FieldI64
| Field::FieldU64
| Field::FieldF32
| Field::FieldF64 => {
let item_ident = Ident::new("yaserde_item", field.get_span());
let inner = enclose_formatted_characters_for_value(&item_ident, label_name);
Some(quote! {
for yaserde_item in &self.#label {
#inner
}
})
}
Field::FieldOption { .. } => Some(quote! {
for item in &self.#label {
if let Some(value) = item {
writer.set_start_event_name(None);
writer.set_skip_start_end(false);
::yaserde::YaSerialize::serialize(value, writer)?;
}
}
}),
Field::FieldStruct { .. } => {
if field.is_flatten() {
Some(quote! {
for item in &self.#label {
writer.set_start_event_name(::std::option::Option::None);
writer.set_skip_start_end(true);
::yaserde::YaSerialize::serialize(item, writer)?;
}
})
} else {
Some(quote! {
for item in &self.#label {
writer.set_start_event_name(::std::option::Option::Some(#label_name.to_string()));
writer.set_skip_start_end(false);
::yaserde::YaSerialize::serialize(item, writer)?;
}
})
}
/*let (start_event, skip_start) = if field.is_flatten() {
(quote!(None), true)
} else {
(quote!(Some(#label_name.to_string())), false)
};
Some(quote! {
writer.set_start_event_name(#start_event);
writer.set_skip_start_end(#skip_start);
::yaserde::YaSerialize::serialize(&self.#label, writer)?;
})*/
}
Field::FieldVec { .. } => {
unimplemented!();
}
},
}
})
.collect();
implement_serializer(
name,
root,
root_attributes,
append_attributes,
struct_inspector,
)
}