use crate::de::Text;
use crate::encoding::Decoder;
use crate::errors::serialize::DeError;
use crate::escape::unescape;
use crate::utils::CowRef;
use memchr::memchr;
use serde::de::value::UnitDeserializer;
use serde::de::{
DeserializeSeed, Deserializer, EnumAccess, IntoDeserializer, SeqAccess, VariantAccess, Visitor,
};
use serde::serde_if_integer128;
use std::borrow::Cow;
use std::ops::Range;
macro_rules! deserialize_num {
($method:ident => $visit:ident) => {
#[inline]
fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let text: &str = self.content.as_ref();
match text.parse() {
Ok(number) => visitor.$visit(number),
Err(_) => self.content.deserialize_str(visitor),
}
}
};
}
macro_rules! deserialize_primitive {
($method:ident) => {
fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let de = AtomicDeserializer {
content: self.decode()?,
escaped: self.escaped,
};
de.$method(visitor)
}
};
}
macro_rules! unsupported {
(
$deserialize:ident
$(
($($type:ty),*)
)?
) => {
#[inline]
fn $deserialize<V: Visitor<'de>>(
self,
$($(_: $type,)*)?
visitor: V
) -> Result<V::Value, Self::Error> {
self.deserialize_str(visitor)
}
};
}
enum Content<'de, 'a> {
Input(&'de str),
Slice(&'a str),
Owned(String, usize),
}
impl<'de, 'a> Content<'de, 'a> {
fn as_str(&self) -> &str {
match self {
Content::Input(s) => s,
Content::Slice(s) => s,
Content::Owned(s, offset) => s.split_at(*offset).1,
}
}
}
struct AtomicDeserializer<'de, 'a> {
content: CowRef<'de, 'a, str>,
escaped: bool,
}
impl<'de, 'a> Deserializer<'de> for AtomicDeserializer<'de, 'a> {
type Error = DeError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.content.deserialize_bool(visitor)
}
deserialize_num!(deserialize_i8 => visit_i8);
deserialize_num!(deserialize_i16 => visit_i16);
deserialize_num!(deserialize_i32 => visit_i32);
deserialize_num!(deserialize_i64 => visit_i64);
deserialize_num!(deserialize_u8 => visit_u8);
deserialize_num!(deserialize_u16 => visit_u16);
deserialize_num!(deserialize_u32 => visit_u32);
deserialize_num!(deserialize_u64 => visit_u64);
serde_if_integer128! {
deserialize_num!(deserialize_i128 => visit_i128);
deserialize_num!(deserialize_u128 => visit_u128);
}
deserialize_num!(deserialize_f32 => visit_f32);
deserialize_num!(deserialize_f64 => visit_f64);
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
if self.escaped {
match unescape(self.content.as_ref())? {
Cow::Borrowed(_) => self.content.deserialize_str(visitor),
Cow::Owned(s) => visitor.visit_string(s),
}
} else {
self.content.deserialize_str(visitor)
}
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let text: &str = self.content.as_ref();
if text.is_empty() {
visitor.visit_none()
} else {
visitor.visit_some(self)
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_enum(self)
}
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
unsupported!(deserialize_bytes);
unsupported!(deserialize_byte_buf);
unsupported!(deserialize_seq);
unsupported!(deserialize_tuple(usize));
unsupported!(deserialize_tuple_struct(&'static str, usize));
unsupported!(deserialize_map);
unsupported!(deserialize_struct(&'static str, &'static [&'static str]));
}
impl<'de, 'a> EnumAccess<'de> for AtomicDeserializer<'de, 'a> {
type Error = DeError;
type Variant = UnitOnly;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), DeError>
where
V: DeserializeSeed<'de>,
{
let name = seed.deserialize(self)?;
Ok((name, UnitOnly))
}
}
pub struct UnitOnly;
impl<'de> VariantAccess<'de> for UnitOnly {
type Error = DeError;
#[inline]
fn unit_variant(self) -> Result<(), Self::Error> {
Ok(())
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
seed.deserialize(UnitDeserializer::<Self::Error>::new())
}
#[inline]
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
#[inline]
fn struct_variant<V>(
self,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
}
struct ListIter<'de, 'a> {
content: Option<Content<'de, 'a>>,
escaped: bool,
}
impl<'de, 'a> SeqAccess<'de> for ListIter<'de, 'a> {
type Error = DeError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, DeError>
where
T: DeserializeSeed<'de>,
{
if let Some(mut content) = self.content.take() {
const DELIMITER: u8 = b' ';
loop {
let string = content.as_str();
if string.is_empty() {
return Ok(None);
}
return match memchr(DELIMITER, string.as_bytes()) {
None => match content {
Content::Input(s) => seed.deserialize(AtomicDeserializer {
content: CowRef::Input(s),
escaped: self.escaped,
}),
Content::Slice(s) => seed.deserialize(AtomicDeserializer {
content: CowRef::Slice(s),
escaped: self.escaped,
}),
Content::Owned(s, 0) => seed.deserialize(AtomicDeserializer {
content: CowRef::Owned(s),
escaped: self.escaped,
}),
Content::Owned(s, offset) => seed.deserialize(AtomicDeserializer {
content: CowRef::Slice(s.split_at(offset).1),
escaped: self.escaped,
}),
},
Some(0) => {
let start = string.as_bytes().iter().position(|ch| *ch != DELIMITER);
content = match (start, content) {
(None, _) => return Ok(None),
(Some(start), Content::Input(s)) => Content::Input(s.split_at(start).1),
(Some(start), Content::Slice(s)) => Content::Slice(s.split_at(start).1),
(Some(start), Content::Owned(s, skip)) => {
Content::Owned(s, skip + start)
}
};
continue;
}
Some(end) => match content {
Content::Input(s) => {
let (item, rest) = s.split_at(end);
self.content = Some(Content::Input(rest));
seed.deserialize(AtomicDeserializer {
content: CowRef::Input(item),
escaped: self.escaped,
})
}
Content::Slice(s) => {
let (item, rest) = s.split_at(end);
self.content = Some(Content::Slice(rest));
seed.deserialize(AtomicDeserializer {
content: CowRef::Slice(item),
escaped: self.escaped,
})
}
Content::Owned(s, skip) => {
let item = s.split_at(skip + end).0;
let result = seed.deserialize(AtomicDeserializer {
content: CowRef::Slice(item),
escaped: self.escaped,
});
self.content = Some(Content::Owned(s, skip + end));
result
}
},
}
.map(Some);
}
}
Ok(None)
}
}
pub struct SimpleTypeDeserializer<'de, 'a> {
content: CowRef<'de, 'a, [u8]>,
escaped: bool,
decoder: Decoder,
}
impl<'de, 'a> SimpleTypeDeserializer<'de, 'a> {
pub fn from_text(text: Cow<'de, str>) -> Self {
let content = match text {
Cow::Borrowed(slice) => CowRef::Input(slice.as_bytes()),
Cow::Owned(content) => CowRef::Owned(content.into_bytes()),
};
Self::new(content, false, Decoder::utf8())
}
pub fn from_text_content(value: Text<'de>) -> Self {
Self::from_text(value.text)
}
#[allow(clippy::ptr_arg)]
pub(crate) fn from_part(
value: &'a Cow<'de, [u8]>,
range: Range<usize>,
escaped: bool,
decoder: Decoder,
) -> Self {
let content = match value {
Cow::Borrowed(slice) => CowRef::Input(&slice[range]),
Cow::Owned(slice) => CowRef::Slice(&slice[range]),
};
Self::new(content, escaped, decoder)
}
#[inline]
const fn new(content: CowRef<'de, 'a, [u8]>, escaped: bool, decoder: Decoder) -> Self {
Self {
content,
escaped,
decoder,
}
}
#[inline]
fn decode<'b>(&'b self) -> Result<CowRef<'de, 'b, str>, DeError> {
Ok(match self.content {
CowRef::Input(content) => match self.decoder.decode(content)? {
Cow::Borrowed(content) => CowRef::Input(content),
Cow::Owned(content) => CowRef::Owned(content),
},
CowRef::Slice(content) => match self.decoder.decode(content)? {
Cow::Borrowed(content) => CowRef::Slice(content),
Cow::Owned(content) => CowRef::Owned(content),
},
CowRef::Owned(ref content) => match self.decoder.decode(content)? {
Cow::Borrowed(content) => CowRef::Slice(content),
Cow::Owned(content) => CowRef::Owned(content),
},
})
}
}
impl<'de, 'a> Deserializer<'de> for SimpleTypeDeserializer<'de, 'a> {
type Error = DeError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
deserialize_primitive!(deserialize_bool);
deserialize_primitive!(deserialize_i8);
deserialize_primitive!(deserialize_i16);
deserialize_primitive!(deserialize_i32);
deserialize_primitive!(deserialize_i64);
deserialize_primitive!(deserialize_u8);
deserialize_primitive!(deserialize_u16);
deserialize_primitive!(deserialize_u32);
deserialize_primitive!(deserialize_u64);
serde_if_integer128! {
deserialize_primitive!(deserialize_i128);
deserialize_primitive!(deserialize_u128);
}
deserialize_primitive!(deserialize_f32);
deserialize_primitive!(deserialize_f64);
deserialize_primitive!(deserialize_str);
#[inline]
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
#[inline]
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
#[inline]
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
#[inline]
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_bytes(visitor)
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_some(self)
}
#[inline]
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
#[inline]
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
let content = match self.decode()? {
CowRef::Input(s) => Content::Input(s),
CowRef::Slice(s) => Content::Slice(s),
CowRef::Owned(s) => Content::Owned(s, 0),
};
visitor.visit_seq(ListIter {
content: Some(content),
escaped: self.escaped,
})
}
#[inline]
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
#[inline]
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_tuple(len, visitor)
}
unsupported!(deserialize_map);
unsupported!(deserialize_struct(&'static str, &'static [&'static str]));
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_enum(self)
}
#[inline]
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
#[inline]
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
}
impl<'de, 'a> EnumAccess<'de> for SimpleTypeDeserializer<'de, 'a> {
type Error = DeError;
type Variant = UnitOnly;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), DeError>
where
V: DeserializeSeed<'de>,
{
let name = seed.deserialize(self)?;
Ok((name, UnitOnly))
}
}
impl<'de, 'a> IntoDeserializer<'de, DeError> for SimpleTypeDeserializer<'de, 'a> {
type Deserializer = Self;
#[inline]
fn into_deserializer(self) -> Self {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::se::simple_type::{QuoteTarget, SimpleTypeSerializer};
use crate::se::QuoteLevel;
use crate::utils::{ByteBuf, Bytes};
use serde::de::IgnoredAny;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
macro_rules! simple_only {
($encoding:ident, $name:ident: $type:ty = $xml:expr => $result:expr) => {
#[test]
fn $name() {
let decoder = Decoder::$encoding();
let xml = $xml;
let de = SimpleTypeDeserializer::new(CowRef::Input(xml.as_ref()), true, decoder);
let data: $type = Deserialize::deserialize(de).unwrap();
assert_eq!(data, $result);
}
};
}
macro_rules! simple {
($encoding:ident, $name:ident: $type:ty = $xml:expr => $result:expr) => {
#[test]
fn $name() {
let decoder = Decoder::$encoding();
let xml = $xml;
let de = SimpleTypeDeserializer::new(CowRef::Input(xml.as_ref()), true, decoder);
let data: $type = Deserialize::deserialize(de).unwrap();
assert_eq!(data, $result);
assert_eq!(
data.serialize(SimpleTypeSerializer {
writer: String::new(),
target: QuoteTarget::Text,
level: QuoteLevel::Full,
})
.unwrap(),
xml
);
}
};
}
macro_rules! err {
($encoding:ident, $name:ident: $type:ty = $xml:expr => $kind:ident($reason:literal)) => {
#[test]
fn $name() {
let decoder = Decoder::$encoding();
let xml = $xml;
let de = SimpleTypeDeserializer::new(CowRef::Input(xml.as_ref()), true, decoder);
let err = <$type as Deserialize>::deserialize(de).unwrap_err();
match err {
DeError::$kind(e) => assert_eq!(e, $reason),
_ => panic!(
"Expected `Err({}({}))`, but got `{:?}`",
stringify!($kind),
$reason,
err
),
}
}
};
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct Unit;
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct Newtype(String);
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct Tuple((), ());
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct BorrowedNewtype<'a>(&'a str);
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct Struct {
key: String,
val: usize,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
enum Enum {
Unit,
Newtype(String),
Tuple(String, usize),
Struct { key: String, val: usize },
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(field_identifier)]
enum Id {
Field,
}
#[derive(Debug, Deserialize)]
#[serde(transparent)]
struct Any(IgnoredAny);
impl PartialEq for Any {
fn eq(&self, _other: &Any) -> bool {
true
}
}
mod atomic {
use super::*;
use crate::se::simple_type::AtomicSerializer;
use pretty_assertions::assert_eq;
use std::ops::Deref;
macro_rules! deserialized_to_only {
($name:ident: $type:ty = $input:literal => $result:expr) => {
#[test]
fn $name() {
let de = AtomicDeserializer {
content: CowRef::Input($input),
escaped: true,
};
let data: $type = Deserialize::deserialize(de).unwrap();
assert_eq!(data, $result);
}
};
}
macro_rules! deserialized_to {
($name:ident: $type:ty = $input:literal => $result:expr) => {
#[test]
fn $name() {
let de = AtomicDeserializer {
content: CowRef::Input($input),
escaped: true,
};
let data: $type = Deserialize::deserialize(de).unwrap();
assert_eq!(data, $result);
let mut buffer = String::new();
let has_written = data
.serialize(AtomicSerializer {
writer: &mut buffer,
target: QuoteTarget::Text,
level: QuoteLevel::Full,
write_delimiter: false,
})
.unwrap();
assert_eq!(buffer, $input);
assert_eq!(has_written, !buffer.is_empty());
}
};
}
macro_rules! err {
($name:ident: $type:ty = $input:literal => $kind:ident($reason:literal)) => {
#[test]
fn $name() {
let de = AtomicDeserializer {
content: CowRef::Input($input),
escaped: true,
};
let err = <$type as Deserialize>::deserialize(de).unwrap_err();
match err {
DeError::$kind(e) => assert_eq!(e, $reason),
_ => panic!(
"Expected `Err({}({}))`, but got `{:?}`",
stringify!($kind),
$reason,
err
),
}
}
};
}
deserialized_to!(false_: bool = "false" => false);
deserialized_to!(true_: bool = "true" => true);
deserialized_to!(i8_: i8 = "-2" => -2);
deserialized_to!(i16_: i16 = "-2" => -2);
deserialized_to!(i32_: i32 = "-2" => -2);
deserialized_to!(i64_: i64 = "-2" => -2);
deserialized_to!(u8_: u8 = "3" => 3);
deserialized_to!(u16_: u16 = "3" => 3);
deserialized_to!(u32_: u32 = "3" => 3);
deserialized_to!(u64_: u64 = "3" => 3);
serde_if_integer128! {
deserialized_to!(i128_: i128 = "-2" => -2);
deserialized_to!(u128_: u128 = "2" => 2);
}
deserialized_to!(f32_: f32 = "1.23" => 1.23);
deserialized_to!(f64_: f64 = "1.23" => 1.23);
deserialized_to!(char_unescaped: char = "h" => 'h');
deserialized_to!(char_escaped: char = "<" => '<');
deserialized_to!(string: String = "<escaped string" => "<escaped string");
deserialized_to_only!(borrowed_str: &str = "non-escaped string" => "non-escaped string");
err!(escaped_str: &str = "escaped string"
=> Custom("invalid type: string \"escaped string\", expected a borrowed string"));
err!(byte_buf: ByteBuf = "<escaped string"
=> Custom("invalid type: string \"<escaped string\", expected byte data"));
err!(borrowed_bytes: Bytes = "non-escaped string"
=> Custom("invalid type: string \"non-escaped string\", expected borrowed bytes"));
deserialized_to!(option_none: Option<&str> = "" => None);
deserialized_to!(option_some: Option<&str> = "non-escaped-string" => Some("non-escaped-string"));
deserialized_to_only!(unit: () = "<root>anything</root>" => ());
deserialized_to_only!(unit_struct: Unit = "<root>anything</root>" => Unit);
deserialized_to!(newtype_owned: Newtype = "<escaped string" => Newtype("<escaped string".into()));
deserialized_to_only!(newtype_borrowed: BorrowedNewtype = "non-escaped string"
=> BorrowedNewtype("non-escaped string"));
err!(seq: Vec<()> = "non-escaped string"
=> Custom("invalid type: string \"non-escaped string\", expected a sequence"));
err!(tuple: ((), ()) = "non-escaped string"
=> Custom("invalid type: string \"non-escaped string\", expected a tuple of size 2"));
err!(tuple_struct: Tuple = "non-escaped string"
=> Custom("invalid type: string \"non-escaped string\", expected tuple struct Tuple"));
err!(map: HashMap<(), ()> = "non-escaped string"
=> Custom("invalid type: string \"non-escaped string\", expected a map"));
err!(struct_: Struct = "non-escaped string"
=> Custom("invalid type: string \"non-escaped string\", expected struct Struct"));
deserialized_to!(enum_unit: Enum = "Unit" => Enum::Unit);
err!(enum_newtype: Enum = "Newtype"
=> Custom("invalid type: unit value, expected a string"));
err!(enum_tuple: Enum = "Tuple"
=> Custom("invalid type: unit value, expected tuple variant Enum::Tuple"));
err!(enum_struct: Enum = "Struct"
=> Custom("invalid type: unit value, expected struct variant Enum::Struct"));
err!(enum_other: Enum = "any data"
=> Custom("unknown variant `any data`, expected one of `Unit`, `Newtype`, `Tuple`, `Struct`"));
deserialized_to_only!(identifier: Id = "Field" => Id::Field);
deserialized_to_only!(ignored_any: Any = "any data" => Any(IgnoredAny));
#[test]
#[cfg(feature = "encoding")]
fn owned_data() {
let de = AtomicDeserializer {
content: CowRef::Owned("string slice".into()),
escaped: true,
};
assert_eq!(de.content.deref(), "string slice");
let data: String = Deserialize::deserialize(de).unwrap();
assert_eq!(data, "string slice");
}
#[test]
fn borrowed_from_deserializer() {
let de = AtomicDeserializer {
content: CowRef::Slice("string slice"),
escaped: true,
};
assert_eq!(de.content.deref(), "string slice");
let data: String = Deserialize::deserialize(de).unwrap();
assert_eq!(data, "string slice");
}
}
mod list {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn empty() {
let mut seq = ListIter {
content: Some(Content::Input("")),
escaped: true,
};
assert_eq!(seq.next_element::<&str>().unwrap(), None);
assert_eq!(seq.next_element::<&str>().unwrap(), None);
}
#[test]
fn only_spaces() {
let mut seq = ListIter {
content: Some(Content::Input(" ")),
escaped: true,
};
assert_eq!(seq.next_element::<&str>().unwrap(), None);
assert_eq!(seq.next_element::<&str>().unwrap(), None);
}
#[test]
fn one_item() {
let mut seq = ListIter {
content: Some(Content::Input("abc")),
escaped: true,
};
assert_eq!(seq.next_element::<&str>().unwrap(), Some("abc"));
assert_eq!(seq.next_element::<&str>().unwrap(), None);
assert_eq!(seq.next_element::<&str>().unwrap(), None);
}
#[test]
fn two_items() {
let mut seq = ListIter {
content: Some(Content::Input("abc def")),
escaped: true,
};
assert_eq!(seq.next_element::<&str>().unwrap(), Some("abc"));
assert_eq!(seq.next_element::<&str>().unwrap(), Some("def"));
assert_eq!(seq.next_element::<&str>().unwrap(), None);
assert_eq!(seq.next_element::<&str>().unwrap(), None);
}
#[test]
fn leading_spaces() {
let mut seq = ListIter {
content: Some(Content::Input(" def")),
escaped: true,
};
assert_eq!(seq.next_element::<&str>().unwrap(), Some("def"));
assert_eq!(seq.next_element::<&str>().unwrap(), None);
assert_eq!(seq.next_element::<&str>().unwrap(), None);
}
#[test]
fn trailing_spaces() {
let mut seq = ListIter {
content: Some(Content::Input("abc ")),
escaped: true,
};
assert_eq!(seq.next_element::<&str>().unwrap(), Some("abc"));
assert_eq!(seq.next_element::<&str>().unwrap(), None);
assert_eq!(seq.next_element::<&str>().unwrap(), None);
}
#[test]
fn mixed_types() {
let mut seq = ListIter {
content: Some(Content::Input("string 1.23 42 true false h Unit")),
escaped: true,
};
assert_eq!(seq.next_element::<&str>().unwrap(), Some("string"));
assert_eq!(seq.next_element::<f32>().unwrap(), Some(1.23));
assert_eq!(seq.next_element::<u32>().unwrap(), Some(42));
assert_eq!(seq.next_element::<bool>().unwrap(), Some(true));
assert_eq!(seq.next_element::<bool>().unwrap(), Some(false));
assert_eq!(seq.next_element::<char>().unwrap(), Some('h'));
assert_eq!(seq.next_element::<Enum>().unwrap(), Some(Enum::Unit));
assert_eq!(seq.next_element::<()>().unwrap(), None);
assert_eq!(seq.next_element::<()>().unwrap(), None);
}
}
mod utf8 {
use super::*;
use pretty_assertions::assert_eq;
simple!(utf8, i8_: i8 = "-2" => -2);
simple!(utf8, i16_: i16 = "-2" => -2);
simple!(utf8, i32_: i32 = "-2" => -2);
simple!(utf8, i64_: i64 = "-2" => -2);
simple!(utf8, u8_: u8 = "3" => 3);
simple!(utf8, u16_: u16 = "3" => 3);
simple!(utf8, u32_: u32 = "3" => 3);
simple!(utf8, u64_: u64 = "3" => 3);
serde_if_integer128! {
simple!(utf8, i128_: i128 = "-2" => -2);
simple!(utf8, u128_: u128 = "2" => 2);
}
simple!(utf8, f32_: f32 = "1.23" => 1.23);
simple!(utf8, f64_: f64 = "1.23" => 1.23);
simple!(utf8, false_: bool = "false" => false);
simple!(utf8, true_: bool = "true" => true);
simple!(utf8, char_unescaped: char = "h" => 'h');
simple!(utf8, char_escaped: char = "<" => '<');
simple!(utf8, string: String = "<escaped string" => "<escaped string");
err!(utf8, byte_buf: ByteBuf = "<escaped string"
=> Custom("invalid type: string \"<escaped string\", expected byte data"));
simple!(utf8, borrowed_str: &str = "non-escaped string" => "non-escaped string");
err!(utf8, borrowed_bytes: Bytes = "<escaped string"
=> Custom("invalid type: string \"<escaped string\", expected borrowed bytes"));
simple!(utf8, option_none: Option<&str> = "" => Some(""));
simple!(utf8, option_some: Option<&str> = "non-escaped string" => Some("non-escaped string"));
simple_only!(utf8, unit: () = "any data" => ());
simple_only!(utf8, unit_struct: Unit = "any data" => Unit);
simple_only!(utf8, newtype_owned: Newtype = "<escaped string"
=> Newtype("<escaped string".into()));
simple_only!(utf8, newtype_borrowed: BorrowedNewtype = "non-escaped string"
=> BorrowedNewtype("non-escaped string"));
err!(utf8, map: HashMap<(), ()> = "any data"
=> Custom("invalid type: string \"any data\", expected a map"));
err!(utf8, struct_: Struct = "any data"
=> Custom("invalid type: string \"any data\", expected struct Struct"));
simple!(utf8, enum_unit: Enum = "Unit" => Enum::Unit);
err!(utf8, enum_newtype: Enum = "Newtype"
=> Custom("invalid type: unit value, expected a string"));
err!(utf8, enum_tuple: Enum = "Tuple"
=> Custom("invalid type: unit value, expected tuple variant Enum::Tuple"));
err!(utf8, enum_struct: Enum = "Struct"
=> Custom("invalid type: unit value, expected struct variant Enum::Struct"));
err!(utf8, enum_other: Enum = "any data"
=> Custom("unknown variant `any data`, expected one of `Unit`, `Newtype`, `Tuple`, `Struct`"));
simple_only!(utf8, identifier: Id = "Field" => Id::Field);
simple_only!(utf8, ignored_any: Any = "any data" => Any(IgnoredAny));
}
#[cfg(feature = "encoding")]
mod utf16 {
use super::*;
use pretty_assertions::assert_eq;
fn to_utf16(string: &str) -> Vec<u8> {
let mut bytes = Vec::new();
for ch in string.encode_utf16() {
bytes.extend_from_slice(&ch.to_le_bytes());
}
bytes
}
macro_rules! utf16 {
($name:ident: $type:ty = $xml:literal => $result:expr) => {
simple_only!(utf16, $name: $type = to_utf16($xml) => $result);
};
}
macro_rules! unsupported {
($name:ident: $type:ty = $xml:literal => $err:literal) => {
err!(utf16, $name: $type = to_utf16($xml) => Custom($err));
};
}
utf16!(i8_: i8 = "-2" => -2);
utf16!(i16_: i16 = "-2" => -2);
utf16!(i32_: i32 = "-2" => -2);
utf16!(i64_: i64 = "-2" => -2);
utf16!(u8_: u8 = "3" => 3);
utf16!(u16_: u16 = "3" => 3);
utf16!(u32_: u32 = "3" => 3);
utf16!(u64_: u64 = "3" => 3);
serde_if_integer128! {
utf16!(i128_: i128 = "-2" => -2);
utf16!(u128_: u128 = "2" => 2);
}
utf16!(f32_: f32 = "1.23" => 1.23);
utf16!(f64_: f64 = "1.23" => 1.23);
utf16!(false_: bool = "false" => false);
utf16!(true_: bool = "true" => true);
utf16!(char_unescaped: char = "h" => 'h');
utf16!(char_escaped: char = "<" => '<');
utf16!(string: String = "<escaped string" => "<escaped string");
unsupported!(borrowed_bytes: Bytes = "<escaped string"
=> "invalid type: string \"<escaped string\", expected borrowed bytes");
utf16!(option_none: Option<()> = "" => Some(()));
utf16!(option_some: Option<()> = "any data" => Some(()));
utf16!(unit: () = "any data" => ());
utf16!(unit_struct: Unit = "any data" => Unit);
utf16!(newtype_owned: Newtype = "<escaped string" => Newtype("<escaped string".into()));
unsupported!(newtype_borrowed: BorrowedNewtype = "non-escaped string"
=> "invalid type: string \"non-escaped string\", expected a borrowed string");
unsupported!(map: HashMap<(), ()> = "any data"
=> "invalid type: string \"any data\", expected a map");
unsupported!(struct_: Struct = "any data"
=> "invalid type: string \"any data\", expected struct Struct");
utf16!(enum_unit: Enum = "Unit" => Enum::Unit);
unsupported!(enum_newtype: Enum = "Newtype"
=> "invalid type: unit value, expected a string");
unsupported!(enum_tuple: Enum = "Tuple"
=> "invalid type: unit value, expected tuple variant Enum::Tuple");
unsupported!(enum_struct: Enum = "Struct"
=> "invalid type: unit value, expected struct variant Enum::Struct");
unsupported!(enum_other: Enum = "any data"
=> "unknown variant `any data`, expected one of `Unit`, `Newtype`, `Tuple`, `Struct`");
utf16!(identifier: Id = "Field" => Id::Field);
utf16!(ignored_any: Any = "any data" => Any(IgnoredAny));
}
}