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 xmlparser::{ElementEnd, Token, Tokenizer};
|
||||||
|
|
||||||
use crate::impls::decode;
|
use crate::impls::{decode, CowStrAccumulator};
|
||||||
use crate::{Error, Id};
|
use crate::{Error, Id};
|
||||||
|
|
||||||
pub struct Deserializer<'cx, 'xml> {
|
pub struct Deserializer<'cx, 'xml> {
|
||||||
|
@ -344,19 +344,21 @@ impl<'xml> Iterator for Context<'xml> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn borrow_cow_str<'xml>(
|
pub fn borrow_cow_str<'a, 'xml: 'a>(
|
||||||
into: &mut Option<Cow<'xml, str>>,
|
into: &mut CowStrAccumulator<'xml, 'a>,
|
||||||
_: &'static str,
|
_: &'static str,
|
||||||
deserializer: &mut Deserializer<'_, 'xml>,
|
deserializer: &mut Deserializer<'_, 'xml>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if into.is_some() {
|
if into.inner.is_some() {
|
||||||
return Err(Error::DuplicateValue);
|
return Err(Error::DuplicateValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(value) = deserializer.take_str()? {
|
let value = match deserializer.take_str()? {
|
||||||
*into = Some(decode(value)?);
|
Some(value) => value,
|
||||||
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
into.inner = Some(decode(value)?);
|
||||||
deserializer.ignore()?;
|
deserializer.ignore()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,11 +319,7 @@ impl<'xml> FromXml<'xml> for &'xml str {
|
||||||
const KIND: Kind = Kind::Scalar;
|
const KIND: Kind = Kind::Scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'xml, 'a, T: ?Sized> FromXml<'xml> for Cow<'a, T>
|
impl<'xml, 'a> FromXml<'xml> for Cow<'a, str> {
|
||||||
where
|
|
||||||
T: ToOwned,
|
|
||||||
T::Owned: FromXml<'xml>,
|
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
|
fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool {
|
||||||
match field {
|
match field {
|
||||||
|
@ -334,20 +330,65 @@ where
|
||||||
|
|
||||||
fn deserialize(
|
fn deserialize(
|
||||||
into: &mut Self::Accumulator,
|
into: &mut Self::Accumulator,
|
||||||
field: &'static str,
|
_: &'static str,
|
||||||
deserializer: &mut Deserializer<'_, 'xml>,
|
deserializer: &mut Deserializer<'_, 'xml>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if into.is_some() {
|
if into.inner.is_some() {
|
||||||
return Err(Error::DuplicateValue);
|
return Err(Error::DuplicateValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut value = <T::Owned as FromXml<'xml>>::Accumulator::default();
|
let value = match deserializer.take_str()? {
|
||||||
T::Owned::deserialize(&mut value, field, deserializer)?;
|
Some(value) => value,
|
||||||
*into = Some(Cow::Owned(value.try_done(field)?));
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
into.inner = Some(decode(value)?.into_owned().into());
|
||||||
Ok(())
|
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;
|
const KIND: Kind = Kind::Scalar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::fmt;
|
use std::{borrow::Cow, fmt};
|
||||||
|
|
||||||
use thiserror::Error;
|
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> {
|
impl<T> Accumulate<Option<T>> for Option<T> {
|
||||||
fn try_done(self, _: &'static str) -> Result<Option<T>, Error> {
|
fn try_done(self, _: &'static str) -> Result<Option<T>, Error> {
|
||||||
Ok(self)
|
Ok(self)
|
||||||
|
|
|
@ -25,13 +25,14 @@ struct StructDeserializerScalars<'a, 'b> {
|
||||||
nested: NestedLifetimes<'a>,
|
nested: NestedLifetimes<'a>,
|
||||||
cow: Cow<'a, str>,
|
cow: Cow<'a, str>,
|
||||||
option: Option<&'a str>,
|
option: Option<&'a str>,
|
||||||
|
slice: Cow<'a, [u8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn scalars() {
|
fn scalars() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
from_str(
|
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{
|
Ok(StructDeserializerScalars{
|
||||||
bool_type: true,
|
bool_type: true,
|
||||||
|
@ -48,13 +49,14 @@ fn scalars() {
|
||||||
},
|
},
|
||||||
cow: Cow::from("123"),
|
cow: Cow::from("123"),
|
||||||
option: None,
|
option: None,
|
||||||
|
slice: Cow::Borrowed(&[1, 2, 3]),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Option none
|
// Option none
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
from_str(
|
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{
|
Ok(StructDeserializerScalars{
|
||||||
bool_type: true,
|
bool_type: true,
|
||||||
|
@ -71,6 +73,7 @@ fn scalars() {
|
||||||
},
|
},
|
||||||
cow: Cow::from("123"),
|
cow: Cow::from("123"),
|
||||||
option: Some("asd"),
|
option: Some("asd"),
|
||||||
|
slice: Cow::Borrowed(&[1, 2, 3]),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue