serializer changes extractet from simple-deserializer branch
This commit is contained in:
parent
3e9f978846
commit
b0e09962bd
|
@ -1,10 +1,15 @@
|
|||
extern crate proc_macro;
|
||||
|
||||
mod se;
|
||||
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use syn::{parse_macro_input, Lit, Meta, NestedMeta};
|
||||
|
||||
use crate::se::Serializer;
|
||||
|
||||
const XML: &str = "xml";
|
||||
|
||||
enum FieldAttribute {
|
||||
|
@ -12,160 +17,40 @@ enum FieldAttribute {
|
|||
PrefixIdentifier(String),
|
||||
}
|
||||
|
||||
struct Serializer {
|
||||
default_namespace: Option<String>,
|
||||
other_namespaces: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl<'a> Serializer {
|
||||
pub fn new(attributes: &'a Vec<syn::Attribute>) -> Serializer {
|
||||
pub(crate) fn get_namespaces(
|
||||
attributes: &Vec<syn::Attribute>,
|
||||
) -> (Option<String>, HashMap<String, String>) {
|
||||
let mut default_namespace = None;
|
||||
let mut other_namespaces = HashMap::default();
|
||||
|
||||
if let Some(list) = Self::retrieve_namespace_list(attributes) {
|
||||
match list.path.get_ident() {
|
||||
Some(ident) if ident == "namespace" => {
|
||||
let list = match retrieve_attr_list("namespace", attributes) {
|
||||
Some(v) => v,
|
||||
None => return (default_namespace, other_namespaces),
|
||||
};
|
||||
|
||||
if list.path.get_ident().unwrap() == "namespace" {
|
||||
let mut iter = list.nested.iter();
|
||||
if let Some(NestedMeta::Lit(Lit::Str(v))) = iter.next() {
|
||||
default_namespace = Some(v.value());
|
||||
}
|
||||
|
||||
for item in iter {
|
||||
match item {
|
||||
NestedMeta::Meta(Meta::NameValue(key)) => {
|
||||
if let NestedMeta::Meta(Meta::NameValue(key)) = item {
|
||||
if let Lit::Str(value) = &key.lit {
|
||||
other_namespaces.insert(
|
||||
key.path.get_ident().unwrap().to_string(),
|
||||
value.value(),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
Serializer {
|
||||
default_namespace,
|
||||
other_namespaces,
|
||||
}
|
||||
}
|
||||
|
||||
fn keys_set(&self) -> BTreeSet<&str> {
|
||||
self.other_namespaces
|
||||
.iter()
|
||||
.map(|(k, _)| k.as_str())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn add_header(&mut self, root_name: &str, output: &'a mut TokenStream) {
|
||||
output.extend(quote!(
|
||||
serializer.output.write_char('<')?;
|
||||
serializer.output.write_str(#root_name)?;
|
||||
));
|
||||
|
||||
if let Some(default_namespace) = self.default_namespace.as_ref() {
|
||||
output.extend(quote!(
|
||||
serializer.output.write_str(" xmlns=\"")?;
|
||||
serializer.output.write_str(#default_namespace)?;
|
||||
serializer.output.write_char('\"')?;
|
||||
));
|
||||
}
|
||||
|
||||
let mut sorted_values: Vec<_> = self.other_namespaces.iter().collect();
|
||||
sorted_values.sort();
|
||||
|
||||
for (key, val) in sorted_values {
|
||||
output.extend(quote!(
|
||||
serializer.output.write_str(" xmlns:")?;
|
||||
serializer.output.write_str(#key)?;
|
||||
serializer.output.write_str("=\"")?;
|
||||
serializer.output.write_str(#val)?;
|
||||
serializer.output.write_char('\"')?;
|
||||
));
|
||||
}
|
||||
output.extend(quote!(
|
||||
serializer.output.write_char('>')?;
|
||||
));
|
||||
}
|
||||
|
||||
fn add_footer(&mut self, root_name: &str, output: &'a mut TokenStream) {
|
||||
output.extend(quote!(
|
||||
serializer.output.write_str("</")?;
|
||||
serializer.output.write_str(#root_name)?;
|
||||
serializer.output.write_char('>')?;
|
||||
));
|
||||
}
|
||||
|
||||
fn process_named_field(
|
||||
&mut self,
|
||||
field: &syn::Field,
|
||||
output: &'a mut TokenStream,
|
||||
missing_prefixes: &'a mut BTreeSet<String>,
|
||||
) {
|
||||
let name = field.ident.as_ref().unwrap().to_string();
|
||||
let field_value = field.ident.as_ref().unwrap();
|
||||
|
||||
output.extend(quote!(
|
||||
let mut field = instant_xml::FieldContext {
|
||||
name: #name,
|
||||
attribute: None,
|
||||
};
|
||||
));
|
||||
|
||||
match Self::retrieve_field_attribute(field) {
|
||||
Some(FieldAttribute::Namespace(namespace_key)) => {
|
||||
output.extend(quote!(
|
||||
field.attribute = Some(instant_xml::FieldAttribute::Namespace(#namespace_key));
|
||||
));
|
||||
}
|
||||
Some(FieldAttribute::PrefixIdentifier(prefix_key)) => {
|
||||
output.extend(quote!(
|
||||
field.attribute = Some(instant_xml::FieldAttribute::Prefix(#prefix_key));
|
||||
));
|
||||
|
||||
if self.other_namespaces.get(&prefix_key).is_none() {
|
||||
missing_prefixes.insert(prefix_key);
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
output.extend(quote!(
|
||||
self.#field_value.serialize(serializer, Some(&field))?;
|
||||
));
|
||||
}
|
||||
|
||||
fn retrieve_namespace_list(attributes: &Vec<syn::Attribute>) -> Option<syn::MetaList> {
|
||||
for attr in attributes {
|
||||
if !attr.path.is_ident(XML) {
|
||||
other_namespaces
|
||||
.insert(key.path.get_ident().unwrap().to_string(), value.value());
|
||||
continue;
|
||||
}
|
||||
|
||||
let nested = match attr.parse_meta() {
|
||||
Ok(Meta::List(meta)) => meta.nested,
|
||||
Ok(_) => todo!(),
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
let list = match nested.first() {
|
||||
Some(NestedMeta::Meta(Meta::List(list))) => list,
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
if list.path.get_ident()? == "namespace" {
|
||||
return Some(list.to_owned());
|
||||
}
|
||||
panic!("Wrong data");
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
(default_namespace, other_namespaces)
|
||||
}
|
||||
|
||||
fn retrieve_field_attribute(input: &syn::Field) -> Option<FieldAttribute> {
|
||||
if let Some(list) = Self::retrieve_namespace_list(&input.attrs) {
|
||||
pub(crate) fn retrieve_field_attribute(name: &str, input: &syn::Field) -> Option<FieldAttribute> {
|
||||
if let Some(list) = retrieve_attr_list(name, &input.attrs) {
|
||||
match list.nested.first() {
|
||||
Some(NestedMeta::Lit(Lit::Str(v))) => {
|
||||
return Some(FieldAttribute::Namespace(v.value()));
|
||||
|
@ -180,6 +65,30 @@ impl<'a> Serializer {
|
|||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn retrieve_attr_list(name: &str, attributes: &Vec<syn::Attribute>) -> Option<syn::MetaList> {
|
||||
for attr in attributes {
|
||||
if !attr.path.is_ident(XML) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let nested = match attr.parse_meta() {
|
||||
Ok(Meta::List(meta)) => meta.nested,
|
||||
Ok(_) => todo!(),
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
let list = match nested.first() {
|
||||
Some(NestedMeta::Meta(Meta::List(list))) => list,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
if list.path.get_ident()? == name {
|
||||
return Some(list.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
#[proc_macro_derive(ToXml, attributes(xml))]
|
||||
|
@ -189,10 +98,8 @@ pub fn to_xml(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|||
let root_name = ident.to_string();
|
||||
let mut missing_prefixes = BTreeSet::new();
|
||||
let mut serializer = Serializer::new(&ast.attrs);
|
||||
|
||||
let mut output = TokenStream::new();
|
||||
|
||||
serializer.add_header(&root_name, &mut output);
|
||||
serializer.add_header(&mut output);
|
||||
|
||||
match &ast.data {
|
||||
syn::Data::Struct(ref data) => {
|
||||
|
@ -212,6 +119,7 @@ pub fn to_xml(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|||
serializer.add_footer(&root_name, &mut output);
|
||||
|
||||
let current_prefixes = serializer.keys_set();
|
||||
|
||||
proc_macro::TokenStream::from(quote!(
|
||||
impl ToXml for #ident {
|
||||
fn serialize<W>(&self, serializer: &mut instant_xml::Serializer<W>, _field_data: Option<&instant_xml::FieldContext>) -> Result<(), instant_xml::Error>
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
use std::collections::{BTreeSet, HashMap};
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
use crate::{get_namespaces, retrieve_field_attribute, FieldAttribute};
|
||||
|
||||
pub struct Serializer {
|
||||
default_namespace: Option<String>,
|
||||
other_namespaces: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl<'a> Serializer {
|
||||
pub fn new(attributes: &'a Vec<syn::Attribute>) -> Serializer {
|
||||
let (default_namespace, other_namespaces) = get_namespaces(attributes);
|
||||
|
||||
Serializer {
|
||||
default_namespace,
|
||||
other_namespaces,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keys_set(&self) -> BTreeSet<&str> {
|
||||
self.other_namespaces
|
||||
.iter()
|
||||
.map(|(k, _)| k.as_str())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn add_header(&mut self, output: &'a mut TokenStream) {
|
||||
output.extend(quote!(
|
||||
serializer.output.write_char('<')?;
|
||||
serializer.output.write_str(field_context.name)?;
|
||||
));
|
||||
|
||||
if let Some(default_namespace) = self.default_namespace.as_ref() {
|
||||
output.extend(quote!(
|
||||
serializer.output.write_str(" xmlns=\"")?;
|
||||
serializer.output.write_str(#default_namespace)?;
|
||||
serializer.output.write_char('\"')?;
|
||||
));
|
||||
}
|
||||
|
||||
let mut sorted_values: Vec<_> = self.other_namespaces.iter().collect();
|
||||
sorted_values.sort();
|
||||
|
||||
for (key, val) in sorted_values {
|
||||
output.extend(quote!(
|
||||
serializer.output.write_str(" xmlns:")?;
|
||||
serializer.output.write_str(#key)?;
|
||||
serializer.output.write_str("=\"")?;
|
||||
serializer.output.write_str(#val)?;
|
||||
serializer.output.write_char('\"')?;
|
||||
));
|
||||
}
|
||||
output.extend(quote!(
|
||||
serializer.output.write_char('>')?;
|
||||
));
|
||||
}
|
||||
|
||||
pub fn add_footer(&mut self, root_name: &str, output: &'a mut TokenStream) {
|
||||
output.extend(quote!(
|
||||
serializer.output.write_str("</")?;
|
||||
serializer.output.write_str(#root_name)?;
|
||||
serializer.output.write_char('>')?;
|
||||
));
|
||||
}
|
||||
|
||||
pub fn process_named_field(
|
||||
&mut self,
|
||||
field: &syn::Field,
|
||||
output: &'a mut TokenStream,
|
||||
missing_prefixes: &'a mut BTreeSet<String>,
|
||||
) {
|
||||
let name = field.ident.as_ref().unwrap().to_string();
|
||||
let field_value = field.ident.as_ref().unwrap();
|
||||
|
||||
output.extend(quote!(
|
||||
let mut field = instant_xml::FieldContext {
|
||||
name: #name,
|
||||
attribute: None,
|
||||
};
|
||||
));
|
||||
|
||||
match retrieve_field_attribute("namespace", field) {
|
||||
Some(FieldAttribute::Namespace(namespace_key)) => {
|
||||
output.extend(quote!(
|
||||
field.attribute = Some(instant_xml::FieldAttribute::Namespace(#namespace_key));
|
||||
));
|
||||
}
|
||||
Some(FieldAttribute::PrefixIdentifier(prefix_key)) => {
|
||||
output.extend(quote!(
|
||||
field.attribute = Some(instant_xml::FieldAttribute::Prefix(#prefix_key));
|
||||
));
|
||||
|
||||
if self.other_namespaces.get(&prefix_key).is_none() {
|
||||
missing_prefixes.insert(prefix_key);
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
output.extend(quote!(
|
||||
self.#field_value.serialize(serializer, Some(&field))?;
|
||||
));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue