Move user-facing serialization interface out of trait
This commit is contained in:
parent
2827bd404e
commit
9577aace57
|
@ -49,7 +49,10 @@ pub fn to_xml(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
|
||||||
proc_macro::TokenStream::from(quote!(
|
proc_macro::TokenStream::from(quote!(
|
||||||
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: ::core::fmt::Write + ?::core::marker::Sized>(
|
||||||
|
&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::ser::FieldContext {
|
let mut field_context = instant_xml::ser::FieldContext {
|
||||||
name: #root_name,
|
name: #root_name,
|
||||||
|
|
|
@ -54,10 +54,10 @@ impl<'a, T> ToXml for DisplayToXml<'a, T>
|
||||||
where
|
where
|
||||||
T: fmt::Display,
|
T: fmt::Display,
|
||||||
{
|
{
|
||||||
fn serialize<W>(&self, serializer: &mut Serializer<W>) -> Result<(), Error>
|
fn serialize<W: fmt::Write + ?Sized>(
|
||||||
where
|
&self,
|
||||||
W: fmt::Write,
|
serializer: &mut Serializer<W>,
|
||||||
{
|
) -> Result<(), Error> {
|
||||||
let field_context = match serializer.consume_field_context() {
|
let field_context = match serializer.consume_field_context() {
|
||||||
Some(field_context) => field_context,
|
Some(field_context) => field_context,
|
||||||
None => return Err(Error::UnexpectedValue),
|
None => return Err(Error::UnexpectedValue),
|
||||||
|
@ -80,7 +80,7 @@ where
|
||||||
macro_rules! to_xml_for_number {
|
macro_rules! to_xml_for_number {
|
||||||
($typ:ty) => {
|
($typ:ty) => {
|
||||||
impl ToXml for $typ {
|
impl ToXml for $typ {
|
||||||
fn serialize<W: fmt::Write>(
|
fn serialize<W: fmt::Write + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
serializer: &mut Serializer<W>,
|
serializer: &mut Serializer<W>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
@ -321,7 +321,10 @@ to_xml_for_number!(f32);
|
||||||
to_xml_for_number!(f64);
|
to_xml_for_number!(f64);
|
||||||
|
|
||||||
impl ToXml for bool {
|
impl ToXml for bool {
|
||||||
fn serialize<W: fmt::Write>(&self, serializer: &mut Serializer<W>) -> Result<(), Error> {
|
fn serialize<W: fmt::Write + ?Sized>(
|
||||||
|
&self,
|
||||||
|
serializer: &mut Serializer<W>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
let value = match self {
|
let value = match self {
|
||||||
true => "true",
|
true => "true",
|
||||||
false => "false",
|
false => "false",
|
||||||
|
@ -332,32 +335,47 @@ impl ToXml for bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToXml for String {
|
impl ToXml for String {
|
||||||
fn serialize<W: fmt::Write>(&self, serializer: &mut Serializer<W>) -> Result<(), Error> {
|
fn serialize<W: fmt::Write + ?Sized>(
|
||||||
|
&self,
|
||||||
|
serializer: &mut Serializer<W>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
DisplayToXml(&escape(self)?).serialize(serializer)
|
DisplayToXml(&escape(self)?).serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToXml for char {
|
impl ToXml for char {
|
||||||
fn serialize<W: fmt::Write>(&self, serializer: &mut Serializer<W>) -> Result<(), Error> {
|
fn serialize<W: fmt::Write + ?Sized>(
|
||||||
|
&self,
|
||||||
|
serializer: &mut Serializer<W>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
let mut tmp = [0u8; 4];
|
let mut tmp = [0u8; 4];
|
||||||
DisplayToXml(&escape(&*self.encode_utf8(&mut tmp))?).serialize(serializer)
|
DisplayToXml(&escape(&*self.encode_utf8(&mut tmp))?).serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToXml for &str {
|
impl ToXml for &str {
|
||||||
fn serialize<W: fmt::Write>(&self, serializer: &mut Serializer<W>) -> Result<(), Error> {
|
fn serialize<W: fmt::Write + ?Sized>(
|
||||||
|
&self,
|
||||||
|
serializer: &mut Serializer<W>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
DisplayToXml(&escape(self)?).serialize(serializer)
|
DisplayToXml(&escape(self)?).serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToXml for Cow<'_, str> {
|
impl ToXml for Cow<'_, str> {
|
||||||
fn serialize<W: fmt::Write>(&self, serializer: &mut Serializer<W>) -> Result<(), Error> {
|
fn serialize<W: fmt::Write + ?Sized>(
|
||||||
|
&self,
|
||||||
|
serializer: &mut Serializer<W>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
DisplayToXml(&escape(self)?).serialize(serializer)
|
DisplayToXml(&escape(self)?).serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ToXml> ToXml for Option<T> {
|
impl<T: ToXml> ToXml for Option<T> {
|
||||||
fn serialize<W: fmt::Write>(&self, serializer: &mut Serializer<W>) -> Result<(), Error> {
|
fn serialize<W: fmt::Write + ?Sized>(
|
||||||
|
&self,
|
||||||
|
serializer: &mut Serializer<W>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
match self {
|
match self {
|
||||||
Some(v) => v.serialize(serializer),
|
Some(v) => v.serialize(serializer),
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
|
|
|
@ -13,14 +13,10 @@ pub mod ser;
|
||||||
pub use ser::Serializer;
|
pub use ser::Serializer;
|
||||||
|
|
||||||
pub trait ToXml {
|
pub trait ToXml {
|
||||||
fn to_xml(&self) -> Result<String, Error> {
|
fn serialize<W: fmt::Write + ?Sized>(
|
||||||
let mut output = String::new();
|
&self,
|
||||||
let mut serializer = Serializer::new(&mut output);
|
serializer: &mut Serializer<W>,
|
||||||
self.serialize(&mut serializer)?;
|
) -> Result<(), Error>;
|
||||||
Ok(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize<W: fmt::Write>(&self, serializer: &mut Serializer<W>) -> Result<(), Error>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FieldAttribute<'xml> {
|
pub enum FieldAttribute<'xml> {
|
||||||
|
@ -45,6 +41,19 @@ pub fn from_str<'xml, T: FromXml<'xml>>(input: &'xml str) -> Result<T, Error> {
|
||||||
T::deserialize(&mut Deserializer::new(input))
|
T::deserialize(&mut Deserializer::new(input))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_string(value: &(impl ToXml + ?Sized)) -> Result<String, Error> {
|
||||||
|
let mut output = String::new();
|
||||||
|
to_writer(value, &mut output)?;
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_writer(
|
||||||
|
value: &(impl ToXml + ?Sized),
|
||||||
|
output: &mut (impl fmt::Write + ?Sized),
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
value.serialize(&mut Serializer::new(output))
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
Scalar,
|
Scalar,
|
||||||
Element(Id<'static>),
|
Element(Id<'static>),
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::fmt::{self, Write};
|
||||||
|
|
||||||
use super::{Error, FieldAttribute};
|
use super::{Error, FieldAttribute};
|
||||||
|
|
||||||
pub struct Serializer<'xml, W: fmt::Write> {
|
pub struct Serializer<'xml, W: fmt::Write + ?Sized> {
|
||||||
// For parent namespaces the key is the namespace and the value is the prefix. We are adding to map
|
// 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.
|
// only if the namespaces do not exist, if it does exist then we are using an already defined parent prefix.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -17,7 +17,7 @@ pub struct Serializer<'xml, W: fmt::Write> {
|
||||||
next_field_context: Option<FieldContext<'xml>>,
|
next_field_context: Option<FieldContext<'xml>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'xml, W: fmt::Write> Serializer<'xml, W> {
|
impl<'xml, W: fmt::Write + ?Sized> Serializer<'xml, W> {
|
||||||
pub fn new(output: &'xml mut W) -> Self {
|
pub fn new(output: &'xml mut W) -> Self {
|
||||||
Self {
|
Self {
|
||||||
parent_namespaces: HashMap::new(),
|
parent_namespaces: HashMap::new(),
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use similar_asserts::assert_eq;
|
use similar_asserts::assert_eq;
|
||||||
|
|
||||||
use instant_xml::{from_str, Error, FromXml, ToXml};
|
use instant_xml::{from_str, to_string, Error, FromXml, ToXml};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, FromXml, ToXml)]
|
#[derive(Debug, PartialEq, Eq, FromXml, ToXml)]
|
||||||
#[xml(ns("URI"))]
|
#[xml(ns("URI"))]
|
||||||
|
@ -57,13 +57,11 @@ fn escape_back() {
|
||||||
#[test]
|
#[test]
|
||||||
fn special_entities() {
|
fn special_entities() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
StructSpecialEntities{
|
to_string(&StructSpecialEntities{
|
||||||
string: "&\"<>\'aa".to_string(),
|
string: "&\"<>\'aa".to_string(),
|
||||||
str: "&\"<>\'bb",
|
str: "&\"<>\'bb",
|
||||||
cow: Cow::from("&\"<>\'cc"),
|
cow: Cow::from("&\"<>\'cc"),
|
||||||
}
|
}).unwrap(),
|
||||||
.to_xml()
|
"<StructSpecialEntities xmlns=\"URI\"><string>&"<>'aa</string><str>&"<>'bb</str><cow>&"<>'cc</cow></StructSpecialEntities>",
|
||||||
.unwrap(),
|
|
||||||
"<StructSpecialEntities xmlns=\"URI\"><string>&"<>'aa</string><str>&"<>'bb</str><cow>&"<>'cc</cow></StructSpecialEntities>"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use similar_asserts::assert_eq;
|
use similar_asserts::assert_eq;
|
||||||
|
|
||||||
use instant_xml::ToXml;
|
use instant_xml::{to_string, ToXml};
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, ToXml)]
|
#[derive(Debug, Eq, PartialEq, ToXml)]
|
||||||
#[xml(ns(dar = "BAZ", internal = "INTERNAL"))]
|
#[xml(ns(dar = "BAZ", internal = "INTERNAL"))]
|
||||||
|
@ -33,7 +33,7 @@ struct Nested {
|
||||||
#[test]
|
#[test]
|
||||||
fn struct_child_namespaces() {
|
fn struct_child_namespaces() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
StructChildNamespaces {
|
to_string(&StructChildNamespaces {
|
||||||
different_child_namespace: NestedDifferentNamespace {
|
different_child_namespace: NestedDifferentNamespace {
|
||||||
flag_parent_prefix: true,
|
flag_parent_prefix: true,
|
||||||
flag_internal_prefix: false,
|
flag_internal_prefix: false,
|
||||||
|
@ -42,8 +42,7 @@ fn struct_child_namespaces() {
|
||||||
flag_parent_prefix: true,
|
flag_parent_prefix: true,
|
||||||
flag_internal_prefix: false,
|
flag_internal_prefix: false,
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
.to_xml()
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"<StructChildNamespaces xmlns=\"URI\" xmlns:bar=\"BAZ\" xmlns:foo=\"BAR\"><NestedDifferentNamespace xmlns=\"\" xmlns:internal=\"INTERNAL\"><bar:flag_parent_prefix>true</bar:flag_parent_prefix><internal:flag_internal_prefix>false</internal:flag_internal_prefix></NestedDifferentNamespace><Nested xmlns:internal=\"INTERNAL\"><bar:flag_parent_prefix>true</bar:flag_parent_prefix><internal:flag_internal_prefix>false</internal:flag_internal_prefix></Nested></StructChildNamespaces>"
|
"<StructChildNamespaces xmlns=\"URI\" xmlns:bar=\"BAZ\" xmlns:foo=\"BAR\"><NestedDifferentNamespace xmlns=\"\" xmlns:internal=\"INTERNAL\"><bar:flag_parent_prefix>true</bar:flag_parent_prefix><internal:flag_internal_prefix>false</internal:flag_internal_prefix></NestedDifferentNamespace><Nested xmlns:internal=\"INTERNAL\"><bar:flag_parent_prefix>true</bar:flag_parent_prefix><internal:flag_internal_prefix>false</internal:flag_internal_prefix></Nested></StructChildNamespaces>"
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use similar_asserts::assert_eq;
|
use similar_asserts::assert_eq;
|
||||||
|
|
||||||
use instant_xml::ToXml;
|
use instant_xml::{to_string, ToXml};
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, ToXml)]
|
#[derive(Debug, Eq, PartialEq, ToXml)]
|
||||||
#[xml(ns(bar = "BAZ", foo = "BAR"))]
|
#[xml(ns(bar = "BAZ", foo = "BAR"))]
|
||||||
|
@ -20,12 +20,11 @@ struct StructWithNamedFields {
|
||||||
#[test]
|
#[test]
|
||||||
fn struct_with_named_fields() {
|
fn struct_with_named_fields() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
StructWithNamedFields {
|
to_string(&StructWithNamedFields {
|
||||||
flag: true,
|
flag: true,
|
||||||
string: "test".to_string(),
|
string: "test".to_string(),
|
||||||
number: 1,
|
number: 1,
|
||||||
}
|
})
|
||||||
.to_xml()
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"<StructWithNamedFields xmlns:bar=\"BAZ\" xmlns:foo=\"BAR\"><flag>true</flag><bar:string>test</bar:string><number xmlns=\"typo\">1</number></StructWithNamedFields>"
|
"<StructWithNamedFields xmlns:bar=\"BAZ\" xmlns:foo=\"BAR\"><flag>true</flag><bar:string>test</bar:string><number xmlns=\"typo\">1</number></StructWithNamedFields>"
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use similar_asserts::assert_eq;
|
use similar_asserts::assert_eq;
|
||||||
|
|
||||||
use instant_xml::ToXml;
|
use instant_xml::{to_string, ToXml};
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, ToXml)]
|
#[derive(Debug, Eq, PartialEq, ToXml)]
|
||||||
#[xml(ns("URI", dar = "BAZ", internal = "INTERNAL"))]
|
#[xml(ns("URI", dar = "BAZ", internal = "INTERNAL"))]
|
||||||
|
@ -37,7 +37,7 @@ struct StructWithCustomField {
|
||||||
#[test]
|
#[test]
|
||||||
fn struct_with_custom_field() {
|
fn struct_with_custom_field() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
StructWithCustomField {
|
to_string(&StructWithCustomField {
|
||||||
int_attribute: 42,
|
int_attribute: 42,
|
||||||
flag_direct_namespace_same_the_same_as_prefix: true,
|
flag_direct_namespace_same_the_same_as_prefix: true,
|
||||||
flag_prefix: false,
|
flag_prefix: false,
|
||||||
|
@ -46,8 +46,7 @@ fn struct_with_custom_field() {
|
||||||
flag_parent_prefix: true,
|
flag_parent_prefix: true,
|
||||||
flag_internal_prefix: false,
|
flag_internal_prefix: false,
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
.to_xml()
|
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"<StructWithCustomField xmlns=\"URI\" xmlns:bar=\"BAZ\" xmlns:foo=\"BAR\" int_attribute=\"42\"><flag_direct_namespace_same_the_same_as_prefix xmlns=\"BAZ\">true</flag_direct_namespace_same_the_same_as_prefix><bar:flag_prefix>false</bar:flag_prefix><flag_direct_namespace xmlns=\"DIFFERENT\">true</flag_direct_namespace><Nested xmlns:internal=\"INTERNAL\"><bar:flag_parent_prefix>true</bar:flag_parent_prefix><internal:flag_internal_prefix>false</internal:flag_internal_prefix></Nested></StructWithCustomField>"
|
"<StructWithCustomField xmlns=\"URI\" xmlns:bar=\"BAZ\" xmlns:foo=\"BAR\" int_attribute=\"42\"><flag_direct_namespace_same_the_same_as_prefix xmlns=\"BAZ\">true</flag_direct_namespace_same_the_same_as_prefix><bar:flag_prefix>false</bar:flag_prefix><flag_direct_namespace xmlns=\"DIFFERENT\">true</flag_direct_namespace><Nested xmlns:internal=\"INTERNAL\"><bar:flag_parent_prefix>true</bar:flag_parent_prefix><internal:flag_internal_prefix>false</internal:flag_internal_prefix></Nested></StructWithCustomField>"
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use similar_asserts::assert_eq;
|
use similar_asserts::assert_eq;
|
||||||
|
|
||||||
use instant_xml::ToXml;
|
use instant_xml::{to_string, ToXml};
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, ToXml)]
|
#[derive(Debug, Eq, PartialEq, ToXml)]
|
||||||
struct Unit;
|
struct Unit;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn unit() {
|
fn unit() {
|
||||||
assert_eq!(Unit.to_xml().unwrap(), "<Unit></Unit>");
|
assert_eq!(to_string(&Unit).unwrap(), "<Unit></Unit>");
|
||||||
//assert_eq!(Unit::from_xml("<Unit/>").unwrap(), Unit);
|
//assert_eq!(Unit::from_xml("<Unit/>").unwrap(), Unit);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue