Move serializer code into ser module
This commit is contained in:
parent
f7bbc00172
commit
9cfee92d03
|
@ -136,7 +136,7 @@ pub fn to_xml(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
impl #generics ToXml for #ident #generics {
|
impl #generics ToXml for #ident #generics {
|
||||||
fn serialize<W: std::fmt::Write>(&self, serializer: &mut instant_xml::Serializer<W>) -> Result<(), instant_xml::Error> {
|
fn serialize<W: std::fmt::Write>(&self, serializer: &mut instant_xml::Serializer<W>) -> Result<(), instant_xml::Error> {
|
||||||
let _ = serializer.consume_field_context();
|
let _ = serializer.consume_field_context();
|
||||||
let mut field_context = instant_xml::FieldContext {
|
let mut field_context = instant_xml::ser::FieldContext {
|
||||||
name: #root_name,
|
name: #root_name,
|
||||||
attribute: None,
|
attribute: None,
|
||||||
};
|
};
|
||||||
|
|
|
@ -81,7 +81,7 @@ impl<'a> Serializer {
|
||||||
let field_value = field.ident.as_ref().unwrap();
|
let field_value = field.ident.as_ref().unwrap();
|
||||||
|
|
||||||
let declaration = quote!(
|
let declaration = quote!(
|
||||||
let mut field = instant_xml::FieldContext {
|
let mut field = instant_xml::ser::FieldContext {
|
||||||
name: #name,
|
name: #name,
|
||||||
attribute: None,
|
attribute: None,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Write;
|
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
pub use xmlparser;
|
|
||||||
|
|
||||||
pub use macros::{FromXml, ToXml};
|
pub use macros::{FromXml, ToXml};
|
||||||
|
|
||||||
mod impls;
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod de;
|
pub mod de;
|
||||||
|
mod impls;
|
||||||
pub use de::Deserializer;
|
pub use de::Deserializer;
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod ser;
|
||||||
|
pub use ser::Serializer;
|
||||||
|
|
||||||
pub trait ToXml {
|
pub trait ToXml {
|
||||||
fn to_xml(&self) -> Result<String, Error> {
|
fn to_xml(&self) -> Result<String, Error> {
|
||||||
|
@ -23,142 +23,12 @@ pub trait ToXml {
|
||||||
fn serialize<W: fmt::Write>(&self, serializer: &mut Serializer<W>) -> Result<(), Error>;
|
fn serialize<W: fmt::Write>(&self, serializer: &mut Serializer<W>) -> Result<(), Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Serializer<'xml, W: fmt::Write> {
|
|
||||||
// For parent namespaces the key is the namespace and the value is the prefix. We are adding to map
|
|
||||||
// only if the namespaces do not exist, if it does exist then we are using an already defined parent prefix.
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub parent_namespaces: HashMap<&'xml str, &'xml str>,
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub output: &'xml mut W,
|
|
||||||
|
|
||||||
parent_default_namespace: &'xml str,
|
|
||||||
parent_default_namespace_to_revert: &'xml str,
|
|
||||||
current_attributes: String,
|
|
||||||
next_field_context: Option<FieldContext<'xml>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'xml, W: fmt::Write> Serializer<'xml, W> {
|
|
||||||
pub fn new(output: &'xml mut W) -> Self {
|
|
||||||
Self {
|
|
||||||
parent_namespaces: HashMap::new(),
|
|
||||||
output,
|
|
||||||
parent_default_namespace: "",
|
|
||||||
parent_default_namespace_to_revert: "",
|
|
||||||
next_field_context: None,
|
|
||||||
current_attributes: String::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn consume_current_attributes(&mut self) -> Result<(), Error> {
|
|
||||||
self.output.write_str(&self.current_attributes)?;
|
|
||||||
self.current_attributes.clear();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_attribute_key(&mut self, attr_key: &impl fmt::Display) -> Result<(), Error> {
|
|
||||||
self.current_attributes.push(' ');
|
|
||||||
write!(self.current_attributes, "{}", attr_key)?;
|
|
||||||
self.current_attributes.push('=');
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_attribute_value(&mut self, attr_value: &impl fmt::Display) -> Result<(), Error> {
|
|
||||||
self.current_attributes.push('"');
|
|
||||||
write!(self.current_attributes, "{}", attr_value)?;
|
|
||||||
self.current_attributes.push('"');
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_field_context(&mut self, field_context: FieldContext<'xml>) -> Result<(), Error> {
|
|
||||||
if self.next_field_context.is_some() {
|
|
||||||
return Err(Error::UnexpectedState);
|
|
||||||
};
|
|
||||||
|
|
||||||
self.next_field_context = Some(field_context);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn consume_field_context(&mut self) -> Option<FieldContext<'xml>> {
|
|
||||||
self.next_field_context.take()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_parent_default_namespace(&mut self, namespace: &'xml str) -> Result<(), Error> {
|
|
||||||
self.parent_default_namespace = namespace;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parent_default_namespace(&self) -> &'xml str {
|
|
||||||
self.parent_default_namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_parent_default_namespace(&mut self, namespace: &'xml str) {
|
|
||||||
self.parent_default_namespace_to_revert = self.parent_default_namespace;
|
|
||||||
self.parent_default_namespace = namespace;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn retrieve_parent_default_namespace(&mut self) {
|
|
||||||
self.parent_default_namespace = self.parent_default_namespace_to_revert;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_open_tag(&mut self, field_context: &FieldContext) -> Result<(), Error> {
|
|
||||||
match field_context.attribute {
|
|
||||||
Some(FieldAttribute::Prefix(prefix)) => {
|
|
||||||
self.output.write_char('<')?;
|
|
||||||
self.output.write_str(prefix)?;
|
|
||||||
self.output.write_char(':')?;
|
|
||||||
self.output.write_str(field_context.name)?;
|
|
||||||
self.output.write_char('>')?;
|
|
||||||
}
|
|
||||||
Some(FieldAttribute::Namespace(namespace))
|
|
||||||
if self.parent_default_namespace != namespace =>
|
|
||||||
{
|
|
||||||
self.output.write_char('<')?;
|
|
||||||
self.output.write_str(field_context.name)?;
|
|
||||||
self.output.write_str(" xmlns=\"")?;
|
|
||||||
self.output.write_str(namespace)?;
|
|
||||||
self.output.write_str("\">")?;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.output.write_char('<')?;
|
|
||||||
self.output.write_str(field_context.name)?;
|
|
||||||
self.output.write_char('>')?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_close_tag(&mut self, field_context: FieldContext) -> Result<(), Error> {
|
|
||||||
match field_context.attribute {
|
|
||||||
Some(FieldAttribute::Prefix(prefix)) => {
|
|
||||||
self.output.write_str("</")?;
|
|
||||||
self.output.write_str(prefix)?;
|
|
||||||
self.output.write_char(':')?;
|
|
||||||
self.output.write_str(field_context.name)?;
|
|
||||||
self.output.write_char('>')?;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.output.write_str("</")?;
|
|
||||||
self.output.write_str(field_context.name)?;
|
|
||||||
self.output.write_char('>')?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum FieldAttribute<'xml> {
|
pub enum FieldAttribute<'xml> {
|
||||||
Prefix(&'xml str),
|
Prefix(&'xml str),
|
||||||
Namespace(&'xml str),
|
Namespace(&'xml str),
|
||||||
Attribute,
|
Attribute,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FieldContext<'xml> {
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub name: &'xml str,
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub attribute: Option<FieldAttribute<'xml>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TagName {
|
pub enum TagName {
|
||||||
FieldName,
|
FieldName,
|
||||||
Custom(&'static str),
|
Custom(&'static str),
|
||||||
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::{self, Write};
|
||||||
|
|
||||||
|
use super::{Error, FieldAttribute};
|
||||||
|
|
||||||
|
pub struct Serializer<'xml, W: fmt::Write> {
|
||||||
|
// For parent namespaces the key is the namespace and the value is the prefix. We are adding to map
|
||||||
|
// only if the namespaces do not exist, if it does exist then we are using an already defined parent prefix.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub parent_namespaces: HashMap<&'xml str, &'xml str>,
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub output: &'xml mut W,
|
||||||
|
|
||||||
|
parent_default_namespace: &'xml str,
|
||||||
|
parent_default_namespace_to_revert: &'xml str,
|
||||||
|
current_attributes: String,
|
||||||
|
next_field_context: Option<FieldContext<'xml>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'xml, W: fmt::Write> Serializer<'xml, W> {
|
||||||
|
pub fn new(output: &'xml mut W) -> Self {
|
||||||
|
Self {
|
||||||
|
parent_namespaces: HashMap::new(),
|
||||||
|
output,
|
||||||
|
parent_default_namespace: "",
|
||||||
|
parent_default_namespace_to_revert: "",
|
||||||
|
next_field_context: None,
|
||||||
|
current_attributes: String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consume_current_attributes(&mut self) -> Result<(), Error> {
|
||||||
|
self.output.write_str(&self.current_attributes)?;
|
||||||
|
self.current_attributes.clear();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_attribute_key(&mut self, attr_key: &impl fmt::Display) -> Result<(), Error> {
|
||||||
|
self.current_attributes.push(' ');
|
||||||
|
write!(self.current_attributes, "{}", attr_key)?;
|
||||||
|
self.current_attributes.push('=');
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_attribute_value(&mut self, attr_value: &impl fmt::Display) -> Result<(), Error> {
|
||||||
|
self.current_attributes.push('"');
|
||||||
|
write!(self.current_attributes, "{}", attr_value)?;
|
||||||
|
self.current_attributes.push('"');
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_field_context(&mut self, field_context: FieldContext<'xml>) -> Result<(), Error> {
|
||||||
|
if self.next_field_context.is_some() {
|
||||||
|
return Err(Error::UnexpectedState);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.next_field_context = Some(field_context);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consume_field_context(&mut self) -> Option<FieldContext<'xml>> {
|
||||||
|
self.next_field_context.take()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_parent_default_namespace(&mut self, namespace: &'xml str) -> Result<(), Error> {
|
||||||
|
self.parent_default_namespace = namespace;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parent_default_namespace(&self) -> &'xml str {
|
||||||
|
self.parent_default_namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_parent_default_namespace(&mut self, namespace: &'xml str) {
|
||||||
|
self.parent_default_namespace_to_revert = self.parent_default_namespace;
|
||||||
|
self.parent_default_namespace = namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn retrieve_parent_default_namespace(&mut self) {
|
||||||
|
self.parent_default_namespace = self.parent_default_namespace_to_revert;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_open_tag(&mut self, field_context: &FieldContext) -> Result<(), Error> {
|
||||||
|
match field_context.attribute {
|
||||||
|
Some(FieldAttribute::Prefix(prefix)) => {
|
||||||
|
self.output.write_char('<')?;
|
||||||
|
self.output.write_str(prefix)?;
|
||||||
|
self.output.write_char(':')?;
|
||||||
|
self.output.write_str(field_context.name)?;
|
||||||
|
self.output.write_char('>')?;
|
||||||
|
}
|
||||||
|
Some(FieldAttribute::Namespace(namespace))
|
||||||
|
if self.parent_default_namespace != namespace =>
|
||||||
|
{
|
||||||
|
self.output.write_char('<')?;
|
||||||
|
self.output.write_str(field_context.name)?;
|
||||||
|
self.output.write_str(" xmlns=\"")?;
|
||||||
|
self.output.write_str(namespace)?;
|
||||||
|
self.output.write_str("\">")?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.output.write_char('<')?;
|
||||||
|
self.output.write_str(field_context.name)?;
|
||||||
|
self.output.write_char('>')?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_close_tag(&mut self, field_context: FieldContext) -> Result<(), Error> {
|
||||||
|
match field_context.attribute {
|
||||||
|
Some(FieldAttribute::Prefix(prefix)) => {
|
||||||
|
self.output.write_str("</")?;
|
||||||
|
self.output.write_str(prefix)?;
|
||||||
|
self.output.write_char(':')?;
|
||||||
|
self.output.write_str(field_context.name)?;
|
||||||
|
self.output.write_char('>')?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.output.write_str("</")?;
|
||||||
|
self.output.write_str(field_context.name)?;
|
||||||
|
self.output.write_char('>')?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FieldContext<'xml> {
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub name: &'xml str,
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub attribute: Option<FieldAttribute<'xml>>,
|
||||||
|
}
|
Loading…
Reference in New Issue