Add support for Cow<'_, [T]>
This commit is contained in:
parent
2e7a48a212
commit
a5795b9b2d
|
@ -3,7 +3,7 @@ use std::collections::{BTreeMap, VecDeque};
|
|||
|
||||
use xmlparser::{ElementEnd, Token, Tokenizer};
|
||||
|
||||
use crate::impls::decode;
|
||||
use crate::impls::{decode, CowStrAccumulator};
|
||||
use crate::{Error, Id};
|
||||
|
||||
pub struct Deserializer<'cx, 'xml> {
|
||||
|
@ -344,19 +344,21 @@ impl<'xml> Iterator for Context<'xml> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn borrow_cow_str<'xml>(
|
||||
into: &mut Option<Cow<'xml, str>>,
|
||||
pub fn borrow_cow_str<'a, 'xml: 'a>(
|
||||
into: &mut CowStrAccumulator<'xml, 'a>,
|
||||
_: &'static str,
|
||||
deserializer: &mut Deserializer<'_, 'xml>,
|
||||
) -> Result<(), Error> {
|
||||
if into.is_some() {
|
||||
if into.inner.is_some() {
|
||||
return Err(Error::DuplicateValue);
|
||||
}
|
||||
|
||||
if let Some(value) = deserializer.take_str()? {
|
||||
*into = Some(decode(value)?);
|
||||
let value = match deserializer.take_str()? {
|
||||
Some(value) => value,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
into.inner = Some(decode(value)?);
|
||||
deserializer.ignore()?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -319,11 +319,7 @@ impl<'xml> FromXml<'xml> for &'xml str {
|
|||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
impl<'xml, 'a, T: ?Sized> FromXml<'xml> for Cow<'a, T>
|
||||
where
|
||||
T: ToOwned,
|
||||
T::Owned: FromXml<'xml>,
|
||||
{
|
||||
impl<'xml, 'a> FromXml<'xml> for Cow<'a, str> {
|
||||
#[inline]
|
||||
fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
|
||||
match field {
|
||||
|
@ -334,20 +330,65 @@ where
|
|||
|
||||
fn deserialize(
|
||||
into: &mut Self::Accumulator,
|
||||
field: &'static str,
|
||||
_: &'static str,
|
||||
deserializer: &mut Deserializer<'_, 'xml>,
|
||||
) -> Result<(), Error> {
|
||||
if into.is_some() {
|
||||
if into.inner.is_some() {
|
||||
return Err(Error::DuplicateValue);
|
||||
}
|
||||
|
||||
let mut value = <T::Owned as FromXml<'xml>>::Accumulator::default();
|
||||
T::Owned::deserialize(&mut value, field, deserializer)?;
|
||||
*into = Some(Cow::Owned(value.try_done(field)?));
|
||||
let value = match deserializer.take_str()? {
|
||||
Some(value) => value,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
into.inner = Some(decode(value)?.into_owned().into());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Option<Cow<'a, T>>;
|
||||
type Accumulator = CowStrAccumulator<'xml, 'a>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CowStrAccumulator<'xml, 'a> {
|
||||
pub(crate) inner: Option<Cow<'a, str>>,
|
||||
marker: PhantomData<&'xml str>,
|
||||
}
|
||||
|
||||
impl<'xml, 'a> Accumulate<Cow<'a, str>> for CowStrAccumulator<'xml, 'a> {
|
||||
fn try_done(self, field: &'static str) -> Result<Cow<'a, str>, Error> {
|
||||
match self.inner {
|
||||
Some(inner) => Ok(inner),
|
||||
None => Err(Error::MissingValue(field)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The `FromXml` implementation for `Cow<'a, [T]>` always builds a `Cow::Owned`:
|
||||
// it is not possible to deserialize into a `Cow::Borrowed` because there's no
|
||||
// place to store the originating slice (length only known at run-time).
|
||||
impl<'xml, 'a, T: FromXml<'xml>> FromXml<'xml> for Cow<'a, [T]>
|
||||
where
|
||||
[T]: ToOwned<Owned = Vec<T>>,
|
||||
{
|
||||
#[inline]
|
||||
fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
|
||||
T::matches(id, field)
|
||||
}
|
||||
|
||||
fn deserialize(
|
||||
into: &mut Self::Accumulator,
|
||||
field: &'static str,
|
||||
deserializer: &mut Deserializer<'_, 'xml>,
|
||||
) -> Result<(), Error> {
|
||||
let mut value = T::Accumulator::default();
|
||||
T::deserialize(&mut value, field, deserializer)?;
|
||||
into.push(value.try_done(field)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
type Accumulator = Vec<T>;
|
||||
const KIND: Kind = Kind::Scalar;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::fmt;
|
||||
use std::{borrow::Cow, fmt};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -66,6 +66,15 @@ impl<T> Accumulate<Vec<T>> for Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Accumulate<Cow<'a, [T]>> for Vec<T>
|
||||
where
|
||||
[T]: ToOwned<Owned = Vec<T>>,
|
||||
{
|
||||
fn try_done(self, _: &'static str) -> Result<Cow<'a, [T]>, Error> {
|
||||
Ok(Cow::Owned(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Accumulate<Option<T>> for Option<T> {
|
||||
fn try_done(self, _: &'static str) -> Result<Option<T>, Error> {
|
||||
Ok(self)
|
||||
|
|
|
@ -25,13 +25,14 @@ struct StructDeserializerScalars<'a, 'b> {
|
|||
nested: NestedLifetimes<'a>,
|
||||
cow: Cow<'a, str>,
|
||||
option: Option<&'a str>,
|
||||
slice: Cow<'a, [u8]>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scalars() {
|
||||
assert_eq!(
|
||||
from_str(
|
||||
"<StructDeserializerScalars xmlns=\"URI\"><bool_type>true</bool_type><i8_type>1</i8_type><u32_type>42</u32_type><string_type>string</string_type><str_type_a>lifetime a</str_type_a><str_type_b>lifetime b</str_type_b><char_type>c</char_type><f32_type>1.20</f32_type><NestedLifetimes><flag>true</flag><str_type_a>asd</str_type_a></NestedLifetimes><cow>123</cow></StructDeserializerScalars>"
|
||||
"<StructDeserializerScalars xmlns=\"URI\"><bool_type>true</bool_type><i8_type>1</i8_type><u32_type>42</u32_type><string_type>string</string_type><str_type_a>lifetime a</str_type_a><str_type_b>lifetime b</str_type_b><char_type>c</char_type><f32_type>1.20</f32_type><NestedLifetimes><flag>true</flag><str_type_a>asd</str_type_a></NestedLifetimes><cow>123</cow><slice>1</slice><slice>2</slice><slice>3</slice></StructDeserializerScalars>"
|
||||
),
|
||||
Ok(StructDeserializerScalars{
|
||||
bool_type: true,
|
||||
|
@ -48,13 +49,14 @@ fn scalars() {
|
|||
},
|
||||
cow: Cow::from("123"),
|
||||
option: None,
|
||||
slice: Cow::Borrowed(&[1, 2, 3]),
|
||||
})
|
||||
);
|
||||
|
||||
// Option none
|
||||
assert_eq!(
|
||||
from_str(
|
||||
"<StructDeserializerScalars xmlns=\"URI\"><bool_type>true</bool_type><i8_type>1</i8_type><u32_type>42</u32_type><string_type>string</string_type><str_type_a>lifetime a</str_type_a><str_type_b>lifetime b</str_type_b><char_type>c</char_type><f32_type>1.2</f32_type><NestedLifetimes><flag>true</flag><str_type_a>asd</str_type_a></NestedLifetimes><cow>123</cow><option>asd</option></StructDeserializerScalars>"
|
||||
"<StructDeserializerScalars xmlns=\"URI\"><bool_type>true</bool_type><i8_type>1</i8_type><u32_type>42</u32_type><string_type>string</string_type><str_type_a>lifetime a</str_type_a><str_type_b>lifetime b</str_type_b><char_type>c</char_type><f32_type>1.2</f32_type><NestedLifetimes><flag>true</flag><str_type_a>asd</str_type_a></NestedLifetimes><cow>123</cow><option>asd</option><slice>1</slice><slice>2</slice><slice>3</slice></StructDeserializerScalars>"
|
||||
),
|
||||
Ok(StructDeserializerScalars{
|
||||
bool_type: true,
|
||||
|
@ -71,6 +73,7 @@ fn scalars() {
|
|||
},
|
||||
cow: Cow::from("123"),
|
||||
option: Some("asd"),
|
||||
slice: Cow::Borrowed(&[1, 2, 3]),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue