mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-16 12:32:18 +00:00
WIP: Start implementing precondition errors
This commit is contained in:
150
crates/xml/derive/src/xml_struct/impl_se.rs
Normal file
150
crates/xml/derive/src/xml_struct/impl_se.rs
Normal file
@@ -0,0 +1,150 @@
|
||||
use quote::quote;
|
||||
|
||||
use crate::{Field, attrs::FieldType};
|
||||
|
||||
use super::NamedStruct;
|
||||
|
||||
impl NamedStruct {
|
||||
pub fn impl_se(&self) -> proc_macro2::TokenStream {
|
||||
let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl();
|
||||
let ident = &self.ident;
|
||||
let tag_writers: Vec<_> = self.fields.iter().filter_map(Field::tag_writer).collect();
|
||||
|
||||
let untagged_attributes = self
|
||||
.fields
|
||||
.iter()
|
||||
.filter(|field| field.attrs.xml_ty == FieldType::Untagged)
|
||||
.filter(|field| !field.attrs.flatten.is_present())
|
||||
.map(|field| {
|
||||
let field_ident = field.target_field_index();
|
||||
quote! {
|
||||
if let Some(attrs) = self.#field_ident.attributes() {
|
||||
bytes_start.extend_attributes(attrs);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let attributes = self
|
||||
.fields
|
||||
.iter()
|
||||
.filter(|field| field.attrs.xml_ty == FieldType::Attr)
|
||||
.map(|field| {
|
||||
let field_name = field.xml_name();
|
||||
let field_index = field.target_field_index();
|
||||
quote! {
|
||||
::quick_xml::events::attributes::Attribute {
|
||||
key: ::quick_xml::name::QName(#field_name),
|
||||
value: ::std::borrow::Cow::from(::rustical_xml::ValueSerialize::serialize(&self.#field_index).into_bytes())
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let tag_name_field = self
|
||||
.fields
|
||||
.iter()
|
||||
.find(|field| field.attrs.xml_ty == FieldType::TagName)
|
||||
.map(|field| {
|
||||
let field_index = field.target_field_index();
|
||||
quote! {
|
||||
let tag_str = self.#field_index.to_string();
|
||||
let tag = Some(tag.unwrap_or(tag_str.as_bytes()));
|
||||
}
|
||||
});
|
||||
|
||||
let namespace_field = self
|
||||
.fields
|
||||
.iter()
|
||||
.find(|field| field.attrs.xml_ty == FieldType::Namespace)
|
||||
.map(|field| {
|
||||
let field_index = field.target_field_index();
|
||||
quote! {
|
||||
let ns = self.#field_index;
|
||||
}
|
||||
});
|
||||
|
||||
let is_empty = tag_writers.is_empty();
|
||||
|
||||
// If we are the root element write the xmlns attributes
|
||||
let prefix_attributes = if self.attrs.root.is_some() {
|
||||
self.attrs
|
||||
.ns_prefix
|
||||
.iter()
|
||||
.map(|(ns, prefix)| {
|
||||
let sep = if !prefix.value().is_empty() {
|
||||
b":".to_vec()
|
||||
} else {
|
||||
b"".to_vec()
|
||||
};
|
||||
let attr_name = [b"xmlns".as_ref(), &sep, &prefix.value()].concat();
|
||||
let a = syn::LitByteStr::new(&attr_name, prefix.span());
|
||||
quote! {
|
||||
bytes_start.push_attribute((#a.as_ref(), #ns.as_ref()));
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
quote! {
|
||||
impl #impl_generics ::rustical_xml::XmlSerialize for #ident #type_generics #where_clause {
|
||||
fn serialize<W: ::std::io::Write>(
|
||||
&self,
|
||||
ns: Option<::quick_xml::name::Namespace>,
|
||||
tag: Option<&[u8]>,
|
||||
namespaces: &::std::collections::HashMap<::quick_xml::name::Namespace, &[u8]>,
|
||||
writer: &mut ::quick_xml::Writer<W>
|
||||
) -> ::std::io::Result<()> {
|
||||
use ::quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
|
||||
|
||||
#tag_name_field;
|
||||
#namespace_field;
|
||||
|
||||
let prefix = ns
|
||||
.map(|ns| namespaces.get(&ns))
|
||||
.unwrap_or(None)
|
||||
.map(|prefix| {
|
||||
if !prefix.is_empty() {
|
||||
[*prefix, b":"].concat()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
});
|
||||
let has_prefix = prefix.is_some();
|
||||
let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat());
|
||||
let qname = tagname.as_ref().map(|tagname| ::quick_xml::name::QName(tagname));
|
||||
//
|
||||
if let Some(qname) = &qname {
|
||||
let mut bytes_start = BytesStart::from(qname.to_owned());
|
||||
if !has_prefix {
|
||||
if let Some(ns) = &ns {
|
||||
bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref()));
|
||||
}
|
||||
}
|
||||
#(#prefix_attributes);*
|
||||
if let Some(attrs) = self.attributes() {
|
||||
bytes_start.extend_attributes(attrs);
|
||||
}
|
||||
#(#untagged_attributes);*
|
||||
if #is_empty {
|
||||
writer.write_event(Event::Empty(bytes_start))?;
|
||||
} else {
|
||||
writer.write_event(Event::Start(bytes_start))?;
|
||||
}
|
||||
}
|
||||
if !#is_empty {
|
||||
#(#tag_writers);*
|
||||
if let Some(qname) = &qname {
|
||||
writer.write_event(Event::End(BytesEnd::from(qname.to_owned())))?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn attributes<'a>(&self) -> Option<Vec<::quick_xml::events::attributes::Attribute<'a>>> {
|
||||
Some(vec![ #(#attributes),* ])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user