Improve support for Vec fields
This commit is contained in:
parent
284a015bf8
commit
aace036ea9
|
@ -42,7 +42,7 @@ fn deserialize_scalar_enum(
|
||||||
};
|
};
|
||||||
|
|
||||||
let serialize_as = meta.serialize_as;
|
let serialize_as = meta.serialize_as;
|
||||||
variants.extend(quote!(Ok(#serialize_as) => Ok(#ident::#v_ident),));
|
variants.extend(quote!(Ok(#serialize_as) => #ident::#v_ident,));
|
||||||
}
|
}
|
||||||
|
|
||||||
let generics = meta.xml_generics();
|
let generics = meta.xml_generics();
|
||||||
|
@ -52,12 +52,22 @@ fn deserialize_scalar_enum(
|
||||||
quote!(
|
quote!(
|
||||||
impl #impl_generics FromXml<'xml> for #ident #ty_generics #where_clause {
|
impl #impl_generics FromXml<'xml> for #ident #ty_generics #where_clause {
|
||||||
fn deserialize<'cx>(
|
fn deserialize<'cx>(
|
||||||
deserializer: &'cx mut ::instant_xml::Deserializer<'cx, 'xml>
|
deserializer: &'cx mut ::instant_xml::Deserializer<'cx, 'xml>,
|
||||||
) -> Result<Self, ::instant_xml::Error> {
|
into: &mut Option<Self>,
|
||||||
match deserializer.take_str() {
|
) -> Result<(), ::instant_xml::Error> {
|
||||||
#variants
|
use ::instant_xml::Error;
|
||||||
_ => Err(::instant_xml::Error::UnexpectedValue)
|
|
||||||
|
if into.is_some() {
|
||||||
|
return Err(Error::DuplicateValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let value = match deserializer.take_str() {
|
||||||
|
#variants
|
||||||
|
_ => return Err(Error::UnexpectedValue),
|
||||||
|
};
|
||||||
|
|
||||||
|
*into = Some(value);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const KIND: ::instant_xml::Kind<'static> = ::instant_xml::Kind::Scalar;
|
const KIND: ::instant_xml::Kind<'static> = ::instant_xml::Kind::Scalar;
|
||||||
|
@ -106,14 +116,14 @@ fn deserialize_wrapped_enum(
|
||||||
}
|
}
|
||||||
|
|
||||||
let v_ident = &variant.ident;
|
let v_ident = &variant.ident;
|
||||||
variants.extend(
|
variants.extend(quote!(if <#no_lifetime_type as FromXml>::KIND.matches(
|
||||||
quote!(if <#no_lifetime_type as FromXml>::KIND.matches(
|
|
||||||
id, ::instant_xml::Id { ns: "", name: "" }
|
id, ::instant_xml::Id { ns: "", name: "" }
|
||||||
) {
|
) {
|
||||||
let mut nested = deserializer.nested(data);
|
let mut nested = deserializer.nested(data);
|
||||||
#ident::#v_ident(#no_lifetime_type::deserialize(&mut nested)?)
|
let mut value = None;
|
||||||
}),
|
#no_lifetime_type::deserialize(&mut nested, &mut value)?;
|
||||||
);
|
*into = value.map(#ident::#v_ident);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = meta.tag();
|
let name = meta.tag();
|
||||||
|
@ -123,7 +133,10 @@ fn deserialize_wrapped_enum(
|
||||||
let (_, ty_generics, where_clause) = input.generics.split_for_impl();
|
let (_, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||||
quote!(
|
quote!(
|
||||||
impl #xml_impl_generics FromXml<'xml> for #ident #ty_generics #where_clause {
|
impl #xml_impl_generics FromXml<'xml> for #ident #ty_generics #where_clause {
|
||||||
fn deserialize<'cx>(deserializer: &'cx mut ::instant_xml::Deserializer<'cx, 'xml>) -> Result<Self, ::instant_xml::Error> {
|
fn deserialize<'cx>(
|
||||||
|
deserializer: &'cx mut ::instant_xml::Deserializer<'cx, 'xml>,
|
||||||
|
into: &mut Option<Self>,
|
||||||
|
) -> Result<(), ::instant_xml::Error> {
|
||||||
use ::instant_xml::de::Node;
|
use ::instant_xml::de::Node;
|
||||||
use ::instant_xml::Error;
|
use ::instant_xml::Error;
|
||||||
|
|
||||||
|
@ -138,7 +151,7 @@ fn deserialize_wrapped_enum(
|
||||||
};
|
};
|
||||||
|
|
||||||
let id = deserializer.element_id(&data)?;
|
let id = deserializer.element_id(&data)?;
|
||||||
let value = #variants else {
|
#variants else {
|
||||||
return Err(Error::UnexpectedTag);
|
return Err(Error::UnexpectedTag);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -146,7 +159,7 @@ fn deserialize_wrapped_enum(
|
||||||
return Err(Error::UnexpectedState("unexpected node after wrapped enum variant"));
|
return Err(Error::UnexpectedState("unexpected node after wrapped enum variant"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(value)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const KIND: ::instant_xml::Kind<'static> = ::instant_xml::Kind::Element(::instant_xml::Id {
|
const KIND: ::instant_xml::Kind<'static> = ::instant_xml::Kind::Element(::instant_xml::Id {
|
||||||
|
@ -236,10 +249,12 @@ fn deserialize_struct(
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
impl #xml_impl_generics FromXml<'xml> for #ident #ty_generics #where_clause {
|
impl #xml_impl_generics FromXml<'xml> for #ident #ty_generics #where_clause {
|
||||||
fn deserialize<'cx>(deserializer: &'cx mut ::instant_xml::Deserializer<'cx, 'xml>) -> Result<Self, ::instant_xml::Error> {
|
fn deserialize<'cx>(
|
||||||
|
deserializer: &'cx mut ::instant_xml::Deserializer<'cx, 'xml>,
|
||||||
|
into: &mut Option<Self>,
|
||||||
|
) -> Result<(), ::instant_xml::Error> {
|
||||||
use ::instant_xml::de::Node;
|
use ::instant_xml::de::Node;
|
||||||
use ::instant_xml::{Error, Id};
|
use ::instant_xml::{Error, Id};
|
||||||
use ::core::marker::PhantomData;
|
|
||||||
|
|
||||||
enum __Elements {
|
enum __Elements {
|
||||||
#elements_enum
|
#elements_enum
|
||||||
|
@ -284,7 +299,8 @@ fn deserialize_struct(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { #return_val })
|
*into = Some(Self { #return_val });
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const KIND: ::instant_xml::Kind<'static> = ::instant_xml::Kind::Element(::instant_xml::Id {
|
const KIND: ::instant_xml::Kind<'static> = ::instant_xml::Kind::Element(::instant_xml::Id {
|
||||||
|
@ -343,23 +359,15 @@ fn process_field(
|
||||||
if !field_meta.attribute {
|
if !field_meta.attribute {
|
||||||
tokens.r#match.extend(quote!(
|
tokens.r#match.extend(quote!(
|
||||||
__Elements::#enum_name => {
|
__Elements::#enum_name => {
|
||||||
if #enum_name.is_some() {
|
|
||||||
return Err(Error::DuplicateValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut nested = deserializer.nested(data);
|
let mut nested = deserializer.nested(data);
|
||||||
#enum_name = Some(<#no_lifetime_type>::deserialize(&mut nested)?);
|
<#no_lifetime_type>::deserialize(&mut nested, &mut #enum_name)?;
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
tokens.r#match.extend(quote!(
|
tokens.r#match.extend(quote!(
|
||||||
__Attributes::#enum_name => {
|
__Attributes::#enum_name => {
|
||||||
if #enum_name.is_some() {
|
|
||||||
return Err(Error::DuplicateValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut nested = deserializer.for_attr(attr);
|
let mut nested = deserializer.for_attr(attr);
|
||||||
#enum_name = Some(<#no_lifetime_type>::deserialize(&mut nested)?);
|
let new = <#no_lifetime_type>::deserialize(&mut nested, &mut #enum_name)?;
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,10 +319,10 @@ fn process_named_field(
|
||||||
discard_lifetimes(&mut no_lifetime_type);
|
discard_lifetimes(&mut no_lifetime_type);
|
||||||
body.extend(quote!(
|
body.extend(quote!(
|
||||||
match <#no_lifetime_type as ToXml>::KIND {
|
match <#no_lifetime_type as ToXml>::KIND {
|
||||||
::instant_xml::Kind::Element(_) => {
|
::instant_xml::Kind::Element(_) | ::instant_xml::Kind::Vec(_) => {
|
||||||
self.#field_name.serialize(serializer)?;
|
self.#field_name.serialize(serializer)?;
|
||||||
}
|
}
|
||||||
::instant_xml::Kind::Scalar | ::instant_xml::Kind::Vec => {
|
::instant_xml::Kind::Scalar => {
|
||||||
let prefix = serializer.write_start(#tag, #ns, true)?;
|
let prefix = serializer.write_start(#tag, #ns, true)?;
|
||||||
serializer.end_start()?;
|
serializer.end_start()?;
|
||||||
self.#field_name.serialize(serializer)?;
|
self.#field_name.serialize(serializer)?;
|
||||||
|
|
|
@ -5,16 +5,26 @@ use std::str::FromStr;
|
||||||
#[cfg(feature = "chrono")]
|
#[cfg(feature = "chrono")]
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
use crate::{de::Node, Deserializer, Error, FromXml, Kind, Serializer, ToXml};
|
use crate::{Deserializer, Error, FromXml, Kind, Serializer, ToXml};
|
||||||
|
|
||||||
// Deserializer
|
// Deserializer
|
||||||
struct FromXmlStr<T: FromStr>(Option<T>);
|
struct FromXmlStr<T: FromStr>(T);
|
||||||
|
|
||||||
impl<'xml, T: FromStr> FromXml<'xml> for FromXmlStr<T> {
|
impl<'xml, T: FromStr> FromXml<'xml> for FromXmlStr<T> {
|
||||||
fn deserialize(deserializer: &mut Deserializer<'_, 'xml>) -> Result<Self, Error> {
|
fn deserialize(
|
||||||
|
deserializer: &mut Deserializer<'_, 'xml>,
|
||||||
|
into: &mut Option<Self>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if into.is_some() {
|
||||||
|
return Err(Error::DuplicateValue);
|
||||||
|
}
|
||||||
|
|
||||||
let value = deserializer.take_str()?;
|
let value = deserializer.take_str()?;
|
||||||
match T::from_str(value) {
|
match T::from_str(value) {
|
||||||
Ok(value) => Ok(Self(Some(value))),
|
Ok(value) => {
|
||||||
|
*into = Some(FromXmlStr(value));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Err(_) => Err(Error::UnexpectedValue),
|
Err(_) => Err(Error::UnexpectedValue),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,10 +33,23 @@ impl<'xml, T: FromStr> FromXml<'xml> for FromXmlStr<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'xml> FromXml<'xml> for bool {
|
impl<'xml> FromXml<'xml> for bool {
|
||||||
fn deserialize<'cx>(deserializer: &'cx mut Deserializer<'cx, 'xml>) -> Result<Self, Error> {
|
fn deserialize<'cx>(
|
||||||
FromXmlStr::<Self>::deserialize(deserializer)?
|
deserializer: &'cx mut Deserializer<'cx, 'xml>,
|
||||||
.0
|
into: &mut Option<Self>,
|
||||||
.ok_or(Error::MissingValue(&Kind::Scalar))
|
) -> Result<(), Error> {
|
||||||
|
if into.is_some() {
|
||||||
|
return Err(Error::DuplicateValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut value = None;
|
||||||
|
FromXmlStr::<Self>::deserialize(deserializer, &mut value)?;
|
||||||
|
match value {
|
||||||
|
Some(value) => {
|
||||||
|
*into = Some(value.0);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => Err(Error::MissingValue(&Kind::Scalar)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const KIND: Kind<'static> = Kind::Scalar;
|
const KIND: Kind<'static> = Kind::Scalar;
|
||||||
|
@ -69,10 +92,21 @@ macro_rules! from_xml_for_number {
|
||||||
impl<'xml> FromXml<'xml> for $typ {
|
impl<'xml> FromXml<'xml> for $typ {
|
||||||
fn deserialize<'cx>(
|
fn deserialize<'cx>(
|
||||||
deserializer: &'cx mut Deserializer<'cx, 'xml>,
|
deserializer: &'cx mut Deserializer<'cx, 'xml>,
|
||||||
) -> Result<Self, Error> {
|
into: &mut Option<Self>,
|
||||||
FromXmlStr::<Self>::deserialize(deserializer)?
|
) -> Result<(), Error> {
|
||||||
.0
|
if into.is_some() {
|
||||||
.ok_or(Error::MissingValue(&Kind::Scalar))
|
return Err(Error::DuplicateValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut value = None;
|
||||||
|
FromXmlStr::<Self>::deserialize(deserializer, &mut value)?;
|
||||||
|
match value {
|
||||||
|
Some(value) => {
|
||||||
|
*into = Some(value.0);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => Err(Error::MissingValue(&Kind::Scalar)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const KIND: Kind<'static> = Kind::Scalar;
|
const KIND: Kind<'static> = Kind::Scalar;
|
||||||
|
@ -94,53 +128,109 @@ from_xml_for_number!(f32);
|
||||||
from_xml_for_number!(f64);
|
from_xml_for_number!(f64);
|
||||||
|
|
||||||
impl<'xml> FromXml<'xml> for char {
|
impl<'xml> FromXml<'xml> for char {
|
||||||
fn deserialize<'cx>(deserializer: &'cx mut Deserializer<'cx, 'xml>) -> Result<Self, Error> {
|
fn deserialize<'cx>(
|
||||||
FromXmlStr::<Self>::deserialize(deserializer)?
|
deserializer: &'cx mut Deserializer<'cx, 'xml>,
|
||||||
.0
|
into: &mut Option<Self>,
|
||||||
.ok_or(Error::MissingValue(&Kind::Scalar))
|
) -> Result<(), Error> {
|
||||||
|
if into.is_some() {
|
||||||
|
return Err(Error::DuplicateValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut value = None;
|
||||||
|
FromXmlStr::<Self>::deserialize(deserializer, &mut value)?;
|
||||||
|
match value {
|
||||||
|
Some(value) => {
|
||||||
|
*into = Some(value.0);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => Err(Error::MissingValue(&Kind::Scalar)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const KIND: Kind<'static> = Kind::Scalar;
|
const KIND: Kind<'static> = Kind::Scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'xml> FromXml<'xml> for String {
|
impl<'xml> FromXml<'xml> for String {
|
||||||
fn deserialize<'cx>(deserializer: &'cx mut Deserializer<'cx, 'xml>) -> Result<Self, Error> {
|
fn deserialize<'cx>(
|
||||||
Ok(<Cow<'xml, str> as FromXml<'xml>>::deserialize(deserializer)?.into_owned())
|
deserializer: &'cx mut Deserializer<'cx, 'xml>,
|
||||||
|
into: &mut Option<Self>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if into.is_some() {
|
||||||
|
return Err(Error::DuplicateValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut value = None;
|
||||||
|
<Cow<'xml, str> as FromXml<'xml>>::deserialize(deserializer, &mut value)?;
|
||||||
|
match value {
|
||||||
|
Some(value) => {
|
||||||
|
*into = Some(value.into_owned());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => Err(Error::MissingValue(&Kind::Scalar)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const KIND: Kind<'static> = Kind::Scalar;
|
const KIND: Kind<'static> = Kind::Scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'xml> FromXml<'xml> for &'xml str {
|
impl<'xml> FromXml<'xml> for &'xml str {
|
||||||
fn deserialize<'cx>(deserializer: &'cx mut Deserializer<'cx, 'xml>) -> Result<Self, Error> {
|
fn deserialize<'cx>(
|
||||||
Ok(
|
deserializer: &'cx mut Deserializer<'cx, 'xml>,
|
||||||
match <Cow<'xml, str> as FromXml<'xml>>::deserialize(deserializer)? {
|
into: &mut Option<Self>,
|
||||||
Cow::Borrowed(s) => s,
|
) -> Result<(), Error> {
|
||||||
Cow::Owned(_) => return Err(Error::UnexpectedValue),
|
if into.is_some() {
|
||||||
},
|
return Err(Error::DuplicateValue);
|
||||||
)
|
}
|
||||||
|
|
||||||
|
let mut value = None;
|
||||||
|
<Cow<'xml, str> as FromXml<'xml>>::deserialize(deserializer, &mut value)?;
|
||||||
|
match value {
|
||||||
|
Some(Cow::Borrowed(s)) => {
|
||||||
|
*into = Some(s);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Some(Cow::Owned(_)) => Err(Error::UnexpectedValue),
|
||||||
|
None => Err(Error::MissingValue(&Kind::Scalar)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const KIND: Kind<'static> = Kind::Scalar;
|
const KIND: Kind<'static> = Kind::Scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'xml> FromXml<'xml> for Cow<'xml, str> {
|
impl<'xml> FromXml<'xml> for Cow<'xml, str> {
|
||||||
fn deserialize(deserializer: &mut Deserializer<'_, 'xml>) -> Result<Self, Error> {
|
fn deserialize(
|
||||||
|
deserializer: &mut Deserializer<'_, 'xml>,
|
||||||
|
into: &mut Option<Self>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if into.is_some() {
|
||||||
|
return Err(Error::DuplicateValue);
|
||||||
|
}
|
||||||
|
|
||||||
let value = deserializer.take_str()?;
|
let value = deserializer.take_str()?;
|
||||||
Ok(decode(value))
|
*into = Some(decode(value));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const KIND: Kind<'static> = Kind::Scalar;
|
const KIND: Kind<'static> = Kind::Scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'xml, T> FromXml<'xml> for Option<T>
|
impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Option<T> {
|
||||||
where
|
fn deserialize<'cx>(
|
||||||
T: FromXml<'xml>,
|
deserializer: &'cx mut Deserializer<'cx, 'xml>,
|
||||||
{
|
into: &mut Option<Self>,
|
||||||
fn deserialize<'cx>(deserializer: &'cx mut Deserializer<'cx, 'xml>) -> Result<Self, Error> {
|
) -> Result<(), Error> {
|
||||||
match <T>::deserialize(deserializer) {
|
if into.is_some() {
|
||||||
Ok(v) => Ok(Some(v)),
|
return Err(Error::DuplicateValue);
|
||||||
Err(e) => Err(e),
|
}
|
||||||
|
|
||||||
|
let mut value = None;
|
||||||
|
<T>::deserialize(deserializer, &mut value)?;
|
||||||
|
match value {
|
||||||
|
Some(v) => {
|
||||||
|
*into = Some(Some(v));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => Err(Error::MissingValue(&Kind::Scalar)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,39 +410,26 @@ fn decode(input: &str) -> Cow<'_, str> {
|
||||||
Cow::Owned(result)
|
Cow::Owned(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
const VEC_LIST_TAG: &str = "list";
|
|
||||||
const VEC_ELEMENT_TAG: &str = "element";
|
|
||||||
|
|
||||||
impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Vec<T> {
|
impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Vec<T> {
|
||||||
fn deserialize<'cx>(deserializer: &'cx mut Deserializer<'cx, 'xml>) -> Result<Self, Error> {
|
fn deserialize<'cx>(
|
||||||
let mut result = Self::new();
|
deserializer: &'cx mut Deserializer<'cx, 'xml>,
|
||||||
let kind = <T as FromXml<'xml>>::KIND;
|
into: &mut Option<Self>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
while let Some(Ok(node)) = deserializer.next() {
|
let mut value = None;
|
||||||
match (&kind, node) {
|
T::deserialize(deserializer, &mut value)?;
|
||||||
(Kind::Scalar, Node::Open(data)) => {
|
let dst = into.get_or_insert(Vec::new());
|
||||||
let id = deserializer.element_id(&data)?;
|
if let Some(value) = value {
|
||||||
|
dst.push(value);
|
||||||
match id.name {
|
|
||||||
VEC_ELEMENT_TAG => {
|
|
||||||
let mut nested = deserializer.nested(data);
|
|
||||||
result.push(<T as FromXml<'xml>>::deserialize(&mut nested)?)
|
|
||||||
}
|
|
||||||
_ => return Err(Error::UnexpectedState("unexpected list element name")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Kind::Vec | Kind::Element(_), Node::Open(data)) => {
|
|
||||||
let mut nested = deserializer.nested(data);
|
|
||||||
result.push(<T as FromXml<'xml>>::deserialize(&mut nested)?)
|
|
||||||
}
|
|
||||||
_ => return Err(Error::UnexpectedState("unexpected node for list")),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const KIND: Kind<'static> = Kind::Vec;
|
fn missing_value() -> Result<Self, Error> {
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
const KIND: Kind<'static> = Kind::Vec(T::KIND.element());
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ToXml> ToXml for Vec<T> {
|
impl<T: ToXml> ToXml for Vec<T> {
|
||||||
|
@ -360,35 +437,19 @@ impl<T: ToXml> ToXml for Vec<T> {
|
||||||
&self,
|
&self,
|
||||||
serializer: &mut Serializer<W>,
|
serializer: &mut Serializer<W>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match <T as ToXml>::KIND {
|
match T::KIND {
|
||||||
Kind::Element(_) => {
|
Kind::Element(_) => {}
|
||||||
|
_ => return Err(Error::UnexpectedState("only elements allowed in `Vec`")),
|
||||||
|
}
|
||||||
|
|
||||||
for i in self {
|
for i in self {
|
||||||
i.serialize(serializer)?;
|
i.serialize(serializer)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Kind::Scalar => {
|
|
||||||
for i in self {
|
|
||||||
let prefix = serializer.write_start(VEC_ELEMENT_TAG, "", false)?;
|
|
||||||
serializer.end_start()?;
|
|
||||||
i.serialize(serializer)?;
|
|
||||||
serializer.write_close(prefix, VEC_ELEMENT_TAG)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// this would be a Vec<Vec<T>>, where the internal field is unnamed
|
|
||||||
Kind::Vec => {
|
|
||||||
for i in self {
|
|
||||||
let prefix = serializer.write_start(VEC_LIST_TAG, "", false)?;
|
|
||||||
serializer.end_start()?;
|
|
||||||
i.serialize(serializer)?;
|
|
||||||
serializer.write_close(prefix, VEC_LIST_TAG)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const KIND: Kind<'static> = Kind::Vec;
|
const KIND: Kind<'static> = Kind::Vec(T::KIND.element());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "chrono")]
|
#[cfg(feature = "chrono")]
|
||||||
|
@ -405,10 +466,20 @@ impl ToXml for DateTime<Utc> {
|
||||||
|
|
||||||
#[cfg(feature = "chrono")]
|
#[cfg(feature = "chrono")]
|
||||||
impl<'xml> FromXml<'xml> for DateTime<Utc> {
|
impl<'xml> FromXml<'xml> for DateTime<Utc> {
|
||||||
fn deserialize<'cx>(deserializer: &'cx mut Deserializer<'cx, 'xml>) -> Result<Self, Error> {
|
fn deserialize<'cx>(
|
||||||
|
deserializer: &'cx mut Deserializer<'cx, 'xml>,
|
||||||
|
into: &mut Option<Self>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if into.is_some() {
|
||||||
|
return Err(Error::DuplicateValue);
|
||||||
|
}
|
||||||
|
|
||||||
let data = deserializer.take_str()?;
|
let data = deserializer.take_str()?;
|
||||||
match DateTime::parse_from_rfc3339(data) {
|
match DateTime::parse_from_rfc3339(data) {
|
||||||
Ok(dt) if dt.timezone().utc_minus_local() == 0 => Ok(dt.with_timezone(&Utc)),
|
Ok(dt) if dt.timezone().utc_minus_local() == 0 => {
|
||||||
|
*into = Some(dt.with_timezone(&Utc));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
_ => Err(Error::Other("invalid date/time".into())),
|
_ => Err(Error::Other("invalid date/time".into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,10 @@ impl<'a, T: ToXml + ?Sized> ToXml for &'a T {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FromXml<'xml>: Sized {
|
pub trait FromXml<'xml>: Sized {
|
||||||
fn deserialize<'cx>(deserializer: &'cx mut Deserializer<'cx, 'xml>) -> Result<Self, Error>;
|
fn deserialize<'cx>(
|
||||||
|
deserializer: &'cx mut Deserializer<'cx, 'xml>,
|
||||||
|
into: &mut Option<Self>,
|
||||||
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
// If the missing field is of type `Option<T>` then treat is as `None`,
|
// If the missing field is of type `Option<T>` then treat is as `None`,
|
||||||
// otherwise it is an error.
|
// otherwise it is an error.
|
||||||
|
@ -50,7 +53,7 @@ pub fn from_str<'xml, T: FromXml<'xml>>(input: &'xml str) -> Result<T, Error> {
|
||||||
let id = context.element_id(&root)?;
|
let id = context.element_id(&root)?;
|
||||||
let expected = match T::KIND {
|
let expected = match T::KIND {
|
||||||
Kind::Scalar => return Err(Error::UnexpectedState("found scalar as root")),
|
Kind::Scalar => return Err(Error::UnexpectedState("found scalar as root")),
|
||||||
Kind::Vec => return Err(Error::UnexpectedState("found list as root")),
|
Kind::Vec(_) => return Err(Error::UnexpectedState("found list as root")),
|
||||||
Kind::Element(expected) => expected,
|
Kind::Element(expected) => expected,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,7 +61,12 @@ pub fn from_str<'xml, T: FromXml<'xml>>(input: &'xml str) -> Result<T, Error> {
|
||||||
return Err(Error::UnexpectedValue);
|
return Err(Error::UnexpectedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
T::deserialize(&mut Deserializer::new(root, &mut context))
|
let mut value = None;
|
||||||
|
T::deserialize(&mut Deserializer::new(root, &mut context), &mut value)?;
|
||||||
|
match value {
|
||||||
|
Some(value) => Ok(value),
|
||||||
|
None => T::missing_value(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string(value: &(impl ToXml + ?Sized)) -> Result<String, Error> {
|
pub fn to_string(value: &(impl ToXml + ?Sized)) -> Result<String, Error> {
|
||||||
|
@ -116,15 +124,22 @@ pub enum Error {
|
||||||
pub enum Kind<'a> {
|
pub enum Kind<'a> {
|
||||||
Scalar,
|
Scalar,
|
||||||
Element(Id<'a>),
|
Element(Id<'a>),
|
||||||
Vec,
|
Vec(Id<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Kind<'a> {
|
impl<'a> Kind<'a> {
|
||||||
|
pub const fn element(&self) -> Id<'a> {
|
||||||
|
match self {
|
||||||
|
Kind::Element(id) => *id,
|
||||||
|
_ => panic!("expected element kind"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn name(&self, field: Id<'a>) -> Id<'a> {
|
pub const fn name(&self, field: Id<'a>) -> Id<'a> {
|
||||||
match self {
|
match self {
|
||||||
Kind::Scalar => field,
|
Kind::Scalar => field,
|
||||||
Kind::Element(name) => *name,
|
Kind::Element(name) => *name,
|
||||||
Kind::Vec => field,
|
Kind::Vec(inner) => *inner,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +148,7 @@ impl<'a> Kind<'a> {
|
||||||
match self {
|
match self {
|
||||||
Kind::Scalar => id == field,
|
Kind::Scalar => id == field,
|
||||||
Kind::Element(name) => id == *name,
|
Kind::Element(name) => id == *name,
|
||||||
Kind::Vec => id == field,
|
Kind::Vec(inner) => id == *inner,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
use instant_xml::{from_str, to_string, FromXml, ToXml};
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, FromXml, PartialEq, ToXml)]
|
||||||
|
struct Foo {
|
||||||
|
bar: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, FromXml, PartialEq, ToXml)]
|
||||||
|
struct Bar {
|
||||||
|
foo: Vec<Foo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn vec() {
|
||||||
|
let val = Bar { foo: vec![] };
|
||||||
|
let xml = "<Bar></Bar>";
|
||||||
|
assert_eq!(xml, to_string(&val).unwrap());
|
||||||
|
assert_eq!(val, from_str(xml).unwrap());
|
||||||
|
|
||||||
|
let val = Bar {
|
||||||
|
foo: vec![Foo { bar: 42 }],
|
||||||
|
};
|
||||||
|
let xml = "<Bar><Foo><bar>42</bar></Foo></Bar>";
|
||||||
|
assert_eq!(xml, to_string(&val).unwrap());
|
||||||
|
assert_eq!(val, from_str(xml).unwrap());
|
||||||
|
|
||||||
|
let val = Bar {
|
||||||
|
foo: vec![Foo { bar: 42 }, Foo { bar: 73 }],
|
||||||
|
};
|
||||||
|
let xml = "<Bar><Foo><bar>42</bar></Foo><Foo><bar>73</bar></Foo></Bar>";
|
||||||
|
assert_eq!(xml, to_string(&val).unwrap());
|
||||||
|
assert_eq!(val, from_str(xml).unwrap());
|
||||||
|
}
|
Loading…
Reference in New Issue