Use associated accumulator type to deserialize into
This commit is contained in:
parent
be7902925e
commit
7a2e6ac735
|
@ -68,7 +68,7 @@ fn deserialize_scalar_enum(
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), ::instant_xml::Error> {
|
||||
use ::instant_xml::Error;
|
||||
|
||||
|
@ -88,6 +88,7 @@ fn deserialize_scalar_enum(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<Self>;
|
||||
const KIND: ::instant_xml::Kind = ::instant_xml::Kind::Scalar;
|
||||
}
|
||||
)
|
||||
|
@ -163,10 +164,10 @@ fn deserialize_forward_enum(
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), ::instant_xml::Error> {
|
||||
use ::instant_xml::de::Node;
|
||||
use ::instant_xml::{Error, FromXml};
|
||||
use ::instant_xml::{Accumulate, Error, FromXml};
|
||||
|
||||
let id = deserializer.parent();
|
||||
#variants else {
|
||||
|
@ -180,6 +181,7 @@ fn deserialize_forward_enum(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<Self>;
|
||||
const KIND: ::instant_xml::Kind = ::instant_xml::Kind::Element;
|
||||
}
|
||||
)
|
||||
|
@ -283,10 +285,10 @@ fn deserialize_struct(
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), ::instant_xml::Error> {
|
||||
use ::instant_xml::de::Node;
|
||||
use ::instant_xml::{Error, FromXml, Id, Kind};
|
||||
use ::instant_xml::{Accumulate, Error, FromXml, Id, Kind};
|
||||
|
||||
enum __Elements {
|
||||
#elements_enum
|
||||
|
@ -336,6 +338,7 @@ fn deserialize_struct(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<Self>;
|
||||
const KIND: ::instant_xml::Kind = ::instant_xml::Kind::Element;
|
||||
}
|
||||
)
|
||||
|
@ -399,7 +402,7 @@ fn named_field(
|
|||
}
|
||||
|
||||
declare_values.extend(quote!(
|
||||
let mut #enum_name: Option<#no_lifetime_type> = None;
|
||||
let mut #enum_name = <#no_lifetime_type as FromXml>::Accumulator::default();
|
||||
));
|
||||
|
||||
let deserialize_with = field_meta
|
||||
|
@ -434,7 +437,7 @@ fn named_field(
|
|||
direct.extend(quote!(
|
||||
Node::Text(text) => {
|
||||
let mut nested = deserializer.for_node(Node::Text(text));
|
||||
FromXml::deserialize(&mut nested, &mut #enum_name)?;
|
||||
<#no_lifetime_type>::deserialize(&mut nested, &mut #enum_name)?;
|
||||
}
|
||||
));
|
||||
} else {
|
||||
|
@ -442,11 +445,11 @@ fn named_field(
|
|||
__Elements::#enum_name => match <#no_lifetime_type as FromXml>::KIND {
|
||||
Kind::Element => {
|
||||
let mut nested = deserializer.nested(data);
|
||||
FromXml::deserialize(&mut nested, &mut #enum_name)?;
|
||||
<#no_lifetime_type>::deserialize(&mut nested, &mut #enum_name)?;
|
||||
}
|
||||
Kind::Scalar => {
|
||||
let mut nested = deserializer.nested(data);
|
||||
FromXml::deserialize(&mut nested, &mut #enum_name)?;
|
||||
<#no_lifetime_type>::deserialize(&mut nested, &mut #enum_name)?;
|
||||
nested.ignore()?;
|
||||
}
|
||||
},
|
||||
|
@ -479,10 +482,7 @@ fn named_field(
|
|||
|
||||
let field_str = format!("{type_name}::{field_name}");
|
||||
return_val.extend(quote!(
|
||||
#field_name: match #enum_name {
|
||||
Some(v) => v,
|
||||
None => <#no_lifetime_type as FromXml>::missing(#field_str)?,
|
||||
},
|
||||
#field_name: #enum_name.try_done(#field_str)?,
|
||||
));
|
||||
|
||||
Ok(())
|
||||
|
@ -540,10 +540,10 @@ fn deserialize_tuple_struct(
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), ::instant_xml::Error> {
|
||||
use ::instant_xml::de::Node;
|
||||
use ::instant_xml::{Error, FromXml, Id, Kind};
|
||||
use ::instant_xml::{Accumulate, Error, FromXml, Id, Kind};
|
||||
|
||||
#declare_values
|
||||
deserializer.ignore()?;
|
||||
|
@ -552,6 +552,7 @@ fn deserialize_tuple_struct(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<Self>;
|
||||
const KIND: ::instant_xml::Kind = ::instant_xml::Kind::Element;
|
||||
}
|
||||
)
|
||||
|
@ -576,7 +577,7 @@ fn unnamed_field(
|
|||
Kind::Element => match deserializer.next() {
|
||||
Some(Ok(Node::Open(data))) => {
|
||||
let mut nested = deserializer.nested(data);
|
||||
let mut value: Option<#no_lifetime_type> = None;
|
||||
let mut value = <#no_lifetime_type as FromXml>::Accumulator::default();
|
||||
<#no_lifetime_type as FromXml>::deserialize(&mut nested, &mut value)?;
|
||||
nested.ignore()?;
|
||||
value
|
||||
|
@ -586,7 +587,7 @@ fn unnamed_field(
|
|||
None => return Err(Error::MissingValue(#field_str)),
|
||||
}
|
||||
Kind::Scalar => {
|
||||
let mut value: Option<#no_lifetime_type> = None;
|
||||
let mut value = <#no_lifetime_type as FromXml>::Accumulator::default();
|
||||
<#no_lifetime_type as FromXml>::deserialize(deserializer, &mut value)?;
|
||||
value
|
||||
}
|
||||
|
@ -595,10 +596,7 @@ fn unnamed_field(
|
|||
|
||||
let field_str = format!("{type_name}::{index}");
|
||||
return_val.extend(quote!(
|
||||
match #name {
|
||||
Some(v) => v,
|
||||
None => <#no_lifetime_type as FromXml>::missing(#field_str)?,
|
||||
},
|
||||
#name.try_done(#field_str)?,
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -620,13 +618,14 @@ fn deserialize_unit_struct(input: &syn::DeriveInput, meta: &ContainerMeta) -> To
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut ::instant_xml::Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), ::instant_xml::Error> {
|
||||
deserializer.ignore()?;
|
||||
*into = Some(Self);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<Self>;
|
||||
const KIND: ::instant_xml::Kind = ::instant_xml::Kind::Element;
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use std::any::type_name;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::net::IpAddr;
|
||||
use std::str::FromStr;
|
||||
use std::{any::type_name, marker::PhantomData};
|
||||
|
||||
#[cfg(feature = "chrono")]
|
||||
use chrono::{DateTime, NaiveDate, Utc};
|
||||
|
||||
use crate::{Deserializer, Error, FromXml, Id, Kind, Serializer, ToXml};
|
||||
use crate::{Accumulate, Deserializer, Error, FromXml, Id, Kind, Serializer, ToXml};
|
||||
|
||||
// Deserializer
|
||||
|
||||
|
@ -49,7 +49,7 @@ impl<'xml, T: FromStr> FromXml<'xml> for FromXmlStr<T> {
|
|||
|
||||
fn deserialize(
|
||||
deserializer: &mut Deserializer<'_, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
if into.is_some() {
|
||||
return Err(Error::DuplicateValue);
|
||||
|
@ -72,6 +72,7 @@ impl<'xml, T: FromStr> FromXml<'xml> for FromXmlStr<T> {
|
|||
}
|
||||
}
|
||||
|
||||
type Accumulator = Option<FromXmlStr<T>>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
|
@ -86,7 +87,7 @@ impl<'xml> FromXml<'xml> for bool {
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
if into.is_some() {
|
||||
return Err(Error::DuplicateValue);
|
||||
|
@ -111,6 +112,7 @@ impl<'xml> FromXml<'xml> for bool {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<bool>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
|
@ -180,7 +182,7 @@ macro_rules! from_xml_for_number {
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
if into.is_some() {
|
||||
return Err(Error::DuplicateValue);
|
||||
|
@ -195,6 +197,7 @@ macro_rules! from_xml_for_number {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<Self>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
};
|
||||
|
@ -224,7 +227,7 @@ impl<'xml> FromXml<'xml> for char {
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
if into.is_some() {
|
||||
return Err(Error::DuplicateValue);
|
||||
|
@ -239,6 +242,7 @@ impl<'xml> FromXml<'xml> for char {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<Self>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
|
@ -253,7 +257,7 @@ impl<'xml> FromXml<'xml> for String {
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
if into.is_some() {
|
||||
return Err(Error::DuplicateValue);
|
||||
|
@ -267,6 +271,7 @@ impl<'xml> FromXml<'xml> for String {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<String>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
|
@ -281,7 +286,7 @@ impl<'xml> FromXml<'xml> for &'xml str {
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
if into.is_some() {
|
||||
return Err(Error::DuplicateValue);
|
||||
|
@ -304,6 +309,7 @@ impl<'xml> FromXml<'xml> for &'xml str {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<&'xml str>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
|
@ -322,21 +328,19 @@ where
|
|||
|
||||
fn deserialize(
|
||||
deserializer: &mut Deserializer<'_, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
if into.is_some() {
|
||||
return Err(Error::DuplicateValue);
|
||||
}
|
||||
|
||||
let mut value = None;
|
||||
let mut value = <T::Owned as FromXml<'xml>>::Accumulator::default();
|
||||
T::Owned::deserialize(deserializer, &mut value)?;
|
||||
if let Some(value) = value {
|
||||
*into = Some(Cow::Owned(value));
|
||||
}
|
||||
|
||||
*into = Some(Cow::Owned(value.try_done("Cow<T>")?));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<Cow<'a, T>>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
|
@ -348,29 +352,37 @@ impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Option<T> {
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
match into.as_mut() {
|
||||
Some(value) => {
|
||||
<T>::deserialize(deserializer, value)?;
|
||||
}
|
||||
None => {
|
||||
let mut value = None;
|
||||
<T>::deserialize(deserializer, &mut value)?;
|
||||
if let Some(value) = value {
|
||||
*into = Some(Some(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<T>::deserialize(deserializer, &mut into.value)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn missing(_: &'static str) -> Result<Self, Error> {
|
||||
Ok(None)
|
||||
type Accumulator = OptionAccumulator<T, T::Accumulator>;
|
||||
const KIND: Kind = <T>::KIND;
|
||||
}
|
||||
|
||||
const KIND: Kind = <T>::KIND;
|
||||
pub struct OptionAccumulator<T, A: Accumulate<T>> {
|
||||
value: A,
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T, A: Accumulate<T>> Default for OptionAccumulator<T, A> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
value: A::default(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A: Accumulate<T>> Accumulate<Option<T>> for OptionAccumulator<T, A> {
|
||||
fn try_done(self, field: &'static str) -> Result<Option<T>, Error> {
|
||||
match self.value.try_done(field) {
|
||||
Ok(value) => Ok(Some(value)),
|
||||
Err(_) => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
to_xml_for_number!(i8);
|
||||
|
@ -556,22 +568,15 @@ impl<'xml, T: FromXml<'xml>> FromXml<'xml> for Vec<T> {
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
let mut value = None;
|
||||
let mut value = T::Accumulator::default();
|
||||
T::deserialize(deserializer, &mut value)?;
|
||||
let dst = into.get_or_insert(Vec::new());
|
||||
if let Some(value) = value {
|
||||
dst.push(value);
|
||||
}
|
||||
|
||||
into.push(value.try_done("Vec<T>")?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn missing(_: &'static str) -> Result<Self, Error> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
type Accumulator = Vec<T>;
|
||||
const KIND: Kind = T::KIND;
|
||||
}
|
||||
|
||||
|
@ -636,7 +641,7 @@ impl<'xml> FromXml<'xml> for DateTime<Utc> {
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
if into.is_some() {
|
||||
return Err(Error::DuplicateValue);
|
||||
|
@ -656,6 +661,7 @@ impl<'xml> FromXml<'xml> for DateTime<Utc> {
|
|||
}
|
||||
}
|
||||
|
||||
type Accumulator = Option<Self>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
|
@ -696,7 +702,7 @@ impl<'xml> FromXml<'xml> for NaiveDate {
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
if into.is_some() {
|
||||
return Err(Error::DuplicateValue);
|
||||
|
@ -716,6 +722,7 @@ impl<'xml> FromXml<'xml> for NaiveDate {
|
|||
}
|
||||
}
|
||||
|
||||
type Accumulator = Option<Self>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
|
@ -730,12 +737,13 @@ impl<'xml> FromXml<'xml> for () {
|
|||
|
||||
fn deserialize<'cx>(
|
||||
_: &mut Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
*into = Some(());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<Self>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
|
@ -760,7 +768,7 @@ impl<'xml> FromXml<'xml> for IpAddr {
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error> {
|
||||
if into.is_some() {
|
||||
return Err(Error::DuplicateValue);
|
||||
|
@ -775,6 +783,7 @@ impl<'xml> FromXml<'xml> for IpAddr {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<Self>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,16 +41,34 @@ pub trait FromXml<'xml>: Sized {
|
|||
|
||||
fn deserialize<'cx>(
|
||||
deserializer: &mut Deserializer<'cx, 'xml>,
|
||||
into: &mut Option<Self>,
|
||||
into: &mut Self::Accumulator,
|
||||
) -> Result<(), Error>;
|
||||
|
||||
// If the missing field is of type `Option<T>` then treat is as `None`,
|
||||
// otherwise it is an error.
|
||||
fn missing(field: &'static str) -> Result<Self, Error> {
|
||||
Err(Error::MissingValue(field))
|
||||
type Accumulator: Accumulate<Self>;
|
||||
const KIND: Kind;
|
||||
}
|
||||
|
||||
const KIND: Kind;
|
||||
/// A type implementing `Accumulate<T>` is used to accumulate a value of type `T`.
|
||||
pub trait Accumulate<T>: Default {
|
||||
fn try_done(self, field: &'static str) -> Result<T, Error>;
|
||||
}
|
||||
|
||||
impl<T> Accumulate<T> for Option<T> {
|
||||
fn try_done(self, field: &'static str) -> Result<T, Error> {
|
||||
self.ok_or(Error::MissingValue(field))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Accumulate<Vec<T>> for Vec<T> {
|
||||
fn try_done(self, _: &'static str) -> Result<Vec<T>, Error> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Accumulate<Option<T>> for Option<T> {
|
||||
fn try_done(self, _: &'static str) -> Result<Option<T>, Error> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str<'xml, T: FromXml<'xml>>(input: &'xml str) -> Result<T, Error> {
|
||||
|
@ -67,12 +85,9 @@ pub fn from_str<'xml, T: FromXml<'xml>>(input: &'xml str) -> Result<T, Error> {
|
|||
}));
|
||||
}
|
||||
|
||||
let mut value = None;
|
||||
let mut value = T::Accumulator::default();
|
||||
T::deserialize(&mut Deserializer::new(root, &mut context), &mut value)?;
|
||||
match value {
|
||||
Some(value) => Ok(value),
|
||||
None => T::missing("<root>"),
|
||||
}
|
||||
value.try_done("root element")
|
||||
}
|
||||
|
||||
pub fn to_string(value: &(impl ToXml + ?Sized)) -> Result<String, Error> {
|
||||
|
|
Loading…
Reference in New Issue