Implement flatten (de)
This commit is contained in:
@@ -13,6 +13,7 @@ pub struct YaSerdeAttribute {
|
||||
pub namespaces: BTreeMap<String, String>,
|
||||
pub attribute: bool,
|
||||
pub text: bool,
|
||||
pub flatten: bool,
|
||||
}
|
||||
|
||||
fn get_value(iter: &mut IntoIter) -> Option<String> {
|
||||
@@ -38,6 +39,7 @@ impl YaSerdeAttribute {
|
||||
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();
|
||||
@@ -78,6 +80,9 @@ impl YaSerdeAttribute {
|
||||
"text" => {
|
||||
text = true;
|
||||
}
|
||||
"flatten" => {
|
||||
flatten = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -95,6 +100,7 @@ impl YaSerdeAttribute {
|
||||
root,
|
||||
default,
|
||||
text,
|
||||
flatten,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,6 +119,7 @@ fn parse_empty_attributes() {
|
||||
namespaces: BTreeMap::new(),
|
||||
attribute: false,
|
||||
text: false,
|
||||
flatten: false,
|
||||
},
|
||||
attrs
|
||||
);
|
||||
@@ -160,6 +167,7 @@ fn parse_attributes() {
|
||||
namespaces: BTreeMap::new(),
|
||||
attribute: true,
|
||||
text: false,
|
||||
flatten: false,
|
||||
},
|
||||
attrs
|
||||
);
|
||||
|
||||
@@ -186,7 +186,7 @@ pub fn parse(
|
||||
let label = &field.ident;
|
||||
let value_label = &get_value_label(&field.ident);
|
||||
|
||||
if field_attrs.attribute {
|
||||
if field_attrs.attribute || field_attrs.flatten {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -288,6 +288,33 @@ pub fn parse(
|
||||
.filter_map(|x| x)
|
||||
.collect();
|
||||
|
||||
let call_flatten_visitors: TokenStream = data_struct
|
||||
.fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
let field_attrs = YaSerdeAttribute::parse(&field.attrs);
|
||||
let value_label = &get_value_label(&field.ident);
|
||||
|
||||
if field_attrs.attribute || !field_attrs.flatten {
|
||||
return None;
|
||||
}
|
||||
|
||||
get_field_type(field).and_then(|f| match f {
|
||||
FieldType::FieldTypeStruct { .. } => Some(quote! {
|
||||
#value_label = yaserde::de::from_str(&unused_xml_elements)?;
|
||||
}),
|
||||
FieldType::FieldTypeOption { data_type } => match *data_type {
|
||||
FieldType::FieldTypeStruct { .. } => Some(quote! {
|
||||
#value_label = yaserde::de::from_str(&unused_xml_elements).ok();
|
||||
}),
|
||||
field_type => unimplemented!("\"flatten\" is not implemented for {:?}", field_type),
|
||||
},
|
||||
field_type => unimplemented!("\"flatten\" is not implemented for {:?}", field_type),
|
||||
})
|
||||
})
|
||||
.filter_map(|x| x)
|
||||
.collect();
|
||||
|
||||
let attributes_loading: TokenStream = data_struct
|
||||
.fields
|
||||
.iter()
|
||||
@@ -410,8 +437,15 @@ pub fn parse(
|
||||
.filter_map(|x| x)
|
||||
.collect();
|
||||
|
||||
let (init_unused, write_unused, visit_unused) = if call_flatten_visitors.is_empty() {
|
||||
(None, None, None)
|
||||
} else {
|
||||
build_code_for_unused_xml_events(&call_flatten_visitors)
|
||||
};
|
||||
|
||||
quote! {
|
||||
use xml::reader::XmlEvent;
|
||||
use xml::reader::{XmlEvent, EventReader};
|
||||
use xml::writer::EventWriter;
|
||||
use yaserde::Visitor;
|
||||
#[allow(unknown_lints, unused_imports)]
|
||||
use std::str::FromStr;
|
||||
@@ -439,15 +473,19 @@ pub fn parse(
|
||||
|
||||
#variables
|
||||
#field_visitors
|
||||
#init_unused
|
||||
|
||||
loop {
|
||||
match reader.peek()?.to_owned() {
|
||||
let event = reader.peek()?.to_owned();
|
||||
|
||||
match event {
|
||||
XmlEvent::StartElement{ref name, ref attributes, ..} => {
|
||||
|
||||
match name.local_name.as_str() {
|
||||
#call_visitors
|
||||
named_element => {
|
||||
let _root = reader.next_event();
|
||||
let event = reader.next_event()?;
|
||||
#write_unused
|
||||
}
|
||||
// name => {
|
||||
// return Err(format!("unknown key {}", name))
|
||||
@@ -457,13 +495,16 @@ pub fn parse(
|
||||
}
|
||||
XmlEvent::EndElement{ref name} => {
|
||||
if name.local_name == named_element {
|
||||
#write_unused
|
||||
break;
|
||||
}
|
||||
let _root = reader.next_event();
|
||||
let event = reader.next_event()?;
|
||||
#write_unused
|
||||
}
|
||||
XmlEvent::Characters(ref text_content) => {
|
||||
#set_text
|
||||
let _root = reader.next_event();
|
||||
let event = reader.next_event()?;
|
||||
#write_unused
|
||||
}
|
||||
event => {
|
||||
return Err(format!("unknown event {:?}", event))
|
||||
@@ -471,6 +512,8 @@ pub fn parse(
|
||||
}
|
||||
}
|
||||
|
||||
#visit_unused
|
||||
|
||||
Ok(#name{#struct_builder})
|
||||
}
|
||||
}
|
||||
@@ -613,3 +656,31 @@ fn build_visitor_ident(label: &str, span: Span, struct_id: Option<&str>) -> Iden
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
fn build_code_for_unused_xml_events(
|
||||
call_flatten_visitors: &TokenStream,
|
||||
) -> (
|
||||
Option<TokenStream>,
|
||||
Option<TokenStream>,
|
||||
Option<TokenStream>,
|
||||
) {
|
||||
(
|
||||
Some(quote! {
|
||||
let mut buf = Vec::new();
|
||||
let mut writer = Some(EventWriter::new(&mut buf));
|
||||
}),
|
||||
Some(quote! {
|
||||
if let Some(ref mut w) = writer {
|
||||
if w.write(event.as_writer_event().unwrap()).is_err() {
|
||||
writer = None;
|
||||
}
|
||||
}
|
||||
}),
|
||||
Some(quote! {
|
||||
if writer.is_some() {
|
||||
let unused_xml_elements = String::from_utf8(buf).unwrap();
|
||||
#call_flatten_visitors
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user