mod escape;
mod map;
mod seq;
mod var;
pub use crate::errors::serialize::DeError;
use crate::{
events::{BytesStart, BytesText, Event},
Reader,
};
use serde::de::{self, DeserializeOwned};
use serde::serde_if_integer128;
use std::io::BufRead;
const INNER_VALUE: &str = "$value";
pub struct Deserializer<R: BufRead> {
reader: Reader<R>,
peek: Option<Event<'static>>,
has_value_field: bool,
}
pub fn from_str<T: DeserializeOwned>(s: &str) -> Result<T, DeError> {
from_reader(s.as_bytes())
}
pub fn from_reader<R: BufRead, T: DeserializeOwned>(reader: R) -> Result<T, DeError> {
let mut de = Deserializer::from_reader(reader);
T::deserialize(&mut de)
}
impl<R: BufRead> Deserializer<R> {
pub fn new(reader: Reader<R>) -> Self {
Deserializer {
reader,
peek: None,
has_value_field: false,
}
}
pub fn from_reader(reader: R) -> Self {
let mut reader = Reader::from_reader(reader);
reader
.expand_empty_elements(true)
.check_end_names(true)
.trim_text(true);
Self::new(reader)
}
fn peek(&mut self) -> Result<Option<&Event<'static>>, DeError> {
if self.peek.is_none() {
self.peek = Some(self.next(&mut Vec::new())?);
}
Ok(self.peek.as_ref())
}
fn next<'a>(&mut self, buf: &'a mut Vec<u8>) -> Result<Event<'static>, DeError> {
if let Some(e) = self.peek.take() {
return Ok(e);
}
loop {
let e = self.reader.read_event(buf)?;
match e {
Event::Start(_) | Event::End(_) | Event::Text(_) | Event::Eof | Event::CData(_) => {
return Ok(e.into_owned())
}
_ => buf.clear(),
}
}
}
fn next_start(&mut self, buf: &mut Vec<u8>) -> Result<Option<BytesStart<'static>>, DeError> {
loop {
let e = self.next(buf)?;
match e {
Event::Start(e) => return Ok(Some(e)),
Event::End(_) => return Err(DeError::End),
Event::Eof => return Ok(None),
_ => buf.clear(),
}
}
}
fn next_text<'a>(&mut self) -> Result<BytesText<'static>, DeError> {
match self.next(&mut Vec::new())? {
Event::Text(e) | Event::CData(e) => Ok(e),
Event::Eof => Err(DeError::Eof),
Event::Start(e) => {
let inner = self.next(&mut Vec::new())?;
let t = match inner {
Event::Text(t) | Event::CData(t) => t,
Event::Start(_) => return Err(DeError::Start),
Event::End(end) if end.name() == e.name() => {
return Ok(BytesText::from_escaped(&[] as &[u8]));
}
Event::End(_) => return Err(DeError::End),
Event::Eof => return Err(DeError::Eof),
_ => unreachable!(),
};
self.read_to_end(e.name())?;
Ok(t)
}
Event::End(e) => {
self.peek = Some(Event::End(e));
Ok(BytesText::from_escaped(&[] as &[u8]))
}
_ => unreachable!(),
}
}
fn read_to_end(&mut self, name: &[u8]) -> Result<(), DeError> {
let mut buf = Vec::new();
match self.next(&mut buf)? {
Event::Start(e) => self.reader.read_to_end(e.name(), &mut Vec::new())?,
Event::End(e) if e.name() == name => return Ok(()),
_ => buf.clear(),
}
Ok(self.reader.read_to_end(name, &mut buf)?)
}
}
macro_rules! deserialize_type {
($deserialize:ident => $visit:ident) => {
fn $deserialize<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
let txt = self.next_text()?;
#[cfg(not(feature = "encoding"))]
let value = self.reader.decode(&*txt)?.parse()?;
#[cfg(feature = "encoding")]
let value = self.reader.decode(&*txt).parse()?;
visitor.$visit(value)
}
};
}
impl<'de, 'a, R: BufRead> de::Deserializer<'de> for &'a mut Deserializer<R> {
type Error = DeError;
fn deserialize_struct<V: de::Visitor<'de>>(
self,
_name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, DeError> {
if let Some(e) = self.next_start(&mut Vec::new())? {
let name = e.name().to_vec();
self.has_value_field = fields.contains(&INNER_VALUE);
let map = map::MapAccess::new(self, e)?;
let value = visitor.visit_map(map)?;
self.has_value_field = false;
self.read_to_end(&name)?;
Ok(value)
} else {
Err(DeError::Start)
}
}
deserialize_type!(deserialize_i8 => visit_i8);
deserialize_type!(deserialize_i16 => visit_i16);
deserialize_type!(deserialize_i32 => visit_i32);
deserialize_type!(deserialize_i64 => visit_i64);
deserialize_type!(deserialize_u8 => visit_u8);
deserialize_type!(deserialize_u16 => visit_u16);
deserialize_type!(deserialize_u32 => visit_u32);
deserialize_type!(deserialize_u64 => visit_u64);
deserialize_type!(deserialize_f32 => visit_f32);
deserialize_type!(deserialize_f64 => visit_f64);
serde_if_integer128! {
deserialize_type!(deserialize_i128 => visit_i128);
deserialize_type!(deserialize_u128 => visit_u128);
}
fn deserialize_bool<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
let txt = self.next_text()?;
#[cfg(feature = "encoding")]
{
#[cfg(feature = "encoding")]
let value = self.reader.decode(&*txt);
match value.as_ref() {
"true" | "1" | "True" | "TRUE" | "t" | "Yes" | "YES" | "yes" | "y" => {
visitor.visit_bool(true)
}
"false" | "0" | "False" | "FALSE" | "f" | "No" | "NO" | "no" | "n" => {
visitor.visit_bool(false)
}
_ => Err(DeError::InvalidBoolean(value.into())),
}
}
#[cfg(not(feature = "encoding"))]
{
match txt.as_ref() {
b"true" | b"1" | b"True" | b"TRUE" | b"t" | b"Yes" | b"YES" | b"yes" | b"y" => {
visitor.visit_bool(true)
}
b"false" | b"0" | b"False" | b"FALSE" | b"f" | b"No" | b"NO" | b"no" | b"n" => {
visitor.visit_bool(false)
}
e => Err(DeError::InvalidBoolean(self.reader.decode(e)?.into())),
}
}
}
fn deserialize_string<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
let value = self.next_text()?.unescape_and_decode(&self.reader)?;
visitor.visit_string(value)
}
fn deserialize_char<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
self.deserialize_string(visitor)
}
fn deserialize_str<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
self.deserialize_string(visitor)
}
fn deserialize_bytes<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
let text = self.next_text()?;
let value = text.escaped();
visitor.visit_bytes(value)
}
fn deserialize_byte_buf<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
let text = self.next_text()?;
let value = text.into_inner().into_owned();
visitor.visit_byte_buf(value)
}
fn deserialize_unit<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
let mut buf = Vec::new();
match self.next(&mut buf)? {
Event::Start(s) => {
self.read_to_end(s.name())?;
visitor.visit_unit()
}
e => Err(DeError::InvalidUnit(format!("{:?}", e))),
}
}
fn deserialize_unit_struct<V: de::Visitor<'de>>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, DeError> {
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V: de::Visitor<'de>>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, DeError> {
self.deserialize_tuple(1, visitor)
}
fn deserialize_tuple<V: de::Visitor<'de>>(
self,
len: usize,
visitor: V,
) -> Result<V::Value, DeError> {
visitor.visit_seq(seq::SeqAccess::new(self, Some(len))?)
}
fn deserialize_tuple_struct<V: de::Visitor<'de>>(
self,
_name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value, DeError> {
self.deserialize_tuple(len, visitor)
}
fn deserialize_enum<V: de::Visitor<'de>>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, DeError> {
let value = visitor.visit_enum(var::EnumAccess::new(self))?;
Ok(value)
}
fn deserialize_seq<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
visitor.visit_seq(seq::SeqAccess::new(self, None)?)
}
fn deserialize_map<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
self.deserialize_struct("", &[], visitor)
}
fn deserialize_option<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
match self.peek()? {
Some(Event::Text(t)) if t.is_empty() => visitor.visit_none(),
None | Some(Event::Eof) => visitor.visit_none(),
_ => visitor.visit_some(self),
}
}
fn deserialize_identifier<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
self.deserialize_string(visitor)
}
fn deserialize_ignored_any<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
match self.next(&mut Vec::new())? {
Event::Start(e) => self.read_to_end(e.name())?,
Event::End(_) => return Err(DeError::End),
_ => (),
}
visitor.visit_unit()
}
fn deserialize_any<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, DeError> {
match self.peek()?.ok_or(DeError::Eof)? {
Event::Start(_) => self.deserialize_map(visitor),
Event::End(_) => self.deserialize_unit(visitor),
_ => self.deserialize_string(visitor),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde::Deserialize;
#[derive(Debug, Deserialize, PartialEq)]
struct Item {
name: String,
source: String,
}
#[test]
fn simple_struct_from_attributes() {
let s = r##"
<item name="hello" source="world.rs" />
"##;
let item: Item = from_str(s).unwrap();
assert_eq!(
item,
Item {
name: "hello".to_string(),
source: "world.rs".to_string(),
}
);
}
#[test]
fn multiple_roots_attributes() {
let s = r##"
<item name="hello" source="world.rs" />
<item name="hello" source="world.rs" />
"##;
let item: Vec<Item> = from_str(s).unwrap();
assert_eq!(
item,
vec![
Item {
name: "hello".to_string(),
source: "world.rs".to_string(),
},
Item {
name: "hello".to_string(),
source: "world.rs".to_string(),
},
]
);
}
#[test]
fn simple_struct_from_attribute_and_child() {
let s = r##"
<item name="hello">
<source>world.rs</source>
</item>
"##;
let item: Item = from_str(s).unwrap();
assert_eq!(
item,
Item {
name: "hello".to_string(),
source: "world.rs".to_string(),
}
);
}
#[derive(Debug, Deserialize, PartialEq)]
struct Project {
name: String,
#[serde(rename = "item", default)]
items: Vec<Item>,
}
#[test]
fn nested_collection() {
let s = r##"
<project name="my_project">
<item name="hello1" source="world1.rs" />
<item name="hello2" source="world2.rs" />
</project>
"##;
let project: Project = from_str(s).unwrap();
assert_eq!(
project,
Project {
name: "my_project".to_string(),
items: vec![
Item {
name: "hello1".to_string(),
source: "world1.rs".to_string(),
},
Item {
name: "hello2".to_string(),
source: "world2.rs".to_string(),
},
],
}
);
}
#[derive(Debug, Deserialize, PartialEq)]
enum MyEnum {
A(String),
B { name: String, flag: bool },
C,
}
#[derive(Debug, Deserialize, PartialEq)]
struct MyEnums {
#[serde(rename = "$value")]
items: Vec<MyEnum>,
}
#[test]
fn collection_of_enums() {
let s = r##"
<enums>
<A>test</A>
<B name="hello" flag="t" />
<C />
</enums>
"##;
let project: MyEnums = from_str(s).unwrap();
assert_eq!(
project,
MyEnums {
items: vec![
MyEnum::A("test".to_string()),
MyEnum::B {
name: "hello".to_string(),
flag: true,
},
MyEnum::C,
],
}
);
}
#[test]
fn deserialize_bytes() {
#[derive(Debug, PartialEq)]
struct Item {
bytes: Vec<u8>,
}
impl<'de> Deserialize<'de> for Item {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
struct ItemVisitor;
impl<'de> de::Visitor<'de> for ItemVisitor {
type Value = Item;
fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
fmt.write_str("byte data")
}
fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
Ok(Item { bytes: v })
}
}
Ok(d.deserialize_byte_buf(ItemVisitor)?)
}
}
let s = r#"<item>bytes</item>"#;
let item: Item = from_reader(s.as_bytes()).unwrap();
assert_eq!(
item,
Item {
bytes: "bytes".as_bytes().to_vec(),
}
);
}
#[test]
fn implicit_value() {
use serde_value::Value;
let s = r#"<root>content</root>"#;
let item: Value = from_str(s).unwrap();
assert_eq!(
item,
Value::Map(
vec![(
Value::String("$value".into()),
Value::String("content".into())
)]
.into_iter()
.collect()
)
);
}
#[test]
fn explicit_value() {
#[derive(Debug, Deserialize, PartialEq)]
struct Item {
#[serde(rename = "$value")]
content: String,
}
let s = r#"<root>content</root>"#;
let item: Item = from_str(s).unwrap();
assert_eq!(
item,
Item {
content: "content".into()
}
);
}
#[test]
fn without_value() {
#[derive(Debug, Deserialize, PartialEq)]
struct Item;
let s = r#"<root>content</root>"#;
let item: Item = from_str(s).unwrap();
assert_eq!(item, Item);
}
#[test]
fn unit() {
#[derive(Debug, Deserialize, PartialEq)]
struct Unit;
let data: Unit = from_str("<root/>").unwrap();
assert_eq!(data, Unit);
}
#[test]
fn newtype() {
#[derive(Debug, Deserialize, PartialEq)]
struct Newtype(bool);
let data: Newtype = from_str("<root>true</root>").unwrap();
assert_eq!(data, Newtype(true));
}
#[test]
fn tuple() {
let data: (f32, String) = from_str("<root>42</root><root>answer</root>").unwrap();
assert_eq!(data, (42.0, "answer".into()));
}
#[test]
fn tuple_struct() {
#[derive(Debug, Deserialize, PartialEq)]
struct Tuple(f32, String);
let data: Tuple = from_str("<root>42</root><root>answer</root>").unwrap();
assert_eq!(data, Tuple(42.0, "answer".into()));
}
mod struct_ {
use super::*;
#[derive(Debug, Deserialize, PartialEq)]
struct Struct {
float: f64,
string: String,
}
#[test]
fn elements() {
let data: Struct =
from_str(r#"<root><float>42</float><string>answer</string></root>"#).unwrap();
assert_eq!(
data,
Struct {
float: 42.0,
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Struct = from_str(r#"<root float="42" string="answer"/>"#).unwrap();
assert_eq!(
data,
Struct {
float: 42.0,
string: "answer".into()
}
);
}
}
mod nested_struct {
use super::*;
#[derive(Debug, Deserialize, PartialEq)]
struct Struct {
nested: Nested,
string: String,
}
#[derive(Debug, Deserialize, PartialEq)]
struct Nested {
float: f32,
}
#[test]
fn elements() {
let data: Struct = from_str(
r#"<root><string>answer</string><nested><float>42</float></nested></root>"#,
)
.unwrap();
assert_eq!(
data,
Struct {
nested: Nested { float: 42.0 },
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Struct =
from_str(r#"<root string="answer"><nested float="42"/></root>"#).unwrap();
assert_eq!(
data,
Struct {
nested: Nested { float: 42.0 },
string: "answer".into()
}
);
}
}
mod flatten_struct {
use super::*;
#[derive(Debug, Deserialize, PartialEq)]
struct Struct {
#[serde(flatten)]
nested: Nested,
string: String,
}
#[derive(Debug, Deserialize, PartialEq)]
struct Nested {
float: String,
}
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn elements() {
let data: Struct =
from_str(r#"<root><float>42</float><string>answer</string></root>"#).unwrap();
assert_eq!(
data,
Struct {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Struct = from_str(r#"<root float="42" string="answer"/>"#).unwrap();
assert_eq!(
data,
Struct {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
}
mod enum_ {
use super::*;
mod externally_tagged {
use super::*;
#[derive(Debug, Deserialize, PartialEq)]
enum Node {
Unit,
Newtype(bool),
Struct {
float: f64,
string: String,
},
Holder {
nested: Nested,
string: String,
},
Flatten {
#[serde(flatten)]
nested: Nested,
string: String,
},
}
#[derive(Debug, Deserialize, PartialEq)]
struct Nested {
float: String,
}
#[derive(Debug, Deserialize, PartialEq)]
enum Workaround {
Tuple(f64, String),
}
#[test]
fn unit() {
let data: Node = from_str("<Unit/>").unwrap();
assert_eq!(data, Node::Unit);
}
#[test]
fn newtype() {
let data: Node = from_str("<Newtype>true</Newtype>").unwrap();
assert_eq!(data, Node::Newtype(true));
}
#[test]
fn tuple_struct() {
let data: Workaround = from_str("<Tuple>42</Tuple><Tuple>answer</Tuple>").unwrap();
assert_eq!(data, Workaround::Tuple(42.0, "answer".into()));
}
mod struct_ {
use super::*;
#[test]
fn elements() {
let data: Node =
from_str(r#"<Struct><float>42</float><string>answer</string></Struct>"#)
.unwrap();
assert_eq!(
data,
Node::Struct {
float: 42.0,
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Node = from_str(r#"<Struct float="42" string="answer"/>"#).unwrap();
assert_eq!(
data,
Node::Struct {
float: 42.0,
string: "answer".into()
}
);
}
}
mod nested_struct {
use super::*;
#[test]
fn elements() {
let data: Node = from_str(
r#"<Holder><string>answer</string><nested><float>42</float></nested></Holder>"#
).unwrap();
assert_eq!(
data,
Node::Holder {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Node =
from_str(r#"<Holder string="answer"><nested float="42"/></Holder>"#)
.unwrap();
assert_eq!(
data,
Node::Holder {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
}
mod flatten_struct {
use super::*;
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn elements() {
let data: Node =
from_str(r#"<Flatten><float>42</float><string>answer</string></Flatten>"#)
.unwrap();
assert_eq!(
data,
Node::Flatten {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Node = from_str(r#"<Flatten float="42" string="answer"/>"#).unwrap();
assert_eq!(
data,
Node::Flatten {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
}
}
mod internally_tagged {
use super::*;
#[derive(Debug, Deserialize, PartialEq)]
#[serde(tag = "tag")]
enum Node {
Unit,
Newtype(NewtypeContent),
Struct {
float: String,
string: String,
},
Holder {
nested: Nested,
string: String,
},
Flatten {
#[serde(flatten)]
nested: Nested,
string: String,
},
}
#[derive(Debug, Deserialize, PartialEq)]
struct NewtypeContent {
value: bool,
}
#[derive(Debug, Deserialize, PartialEq)]
struct Nested {
float: String,
}
mod unit {
use super::*;
#[test]
fn elements() {
let data: Node = from_str(r#"<root><tag>Unit</tag></root>"#).unwrap();
assert_eq!(data, Node::Unit);
}
#[test]
fn attributes() {
let data: Node = from_str(r#"<root tag="Unit"/>"#).unwrap();
assert_eq!(data, Node::Unit);
}
}
mod newtype {
use super::*;
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn elements() {
let data: Node =
from_str(r#"<root><tag>Newtype</tag><value>true</value></root>"#).unwrap();
assert_eq!(data, Node::Newtype(NewtypeContent { value: true }));
}
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn attributes() {
let data: Node = from_str(r#"<root tag="Newtype" value="true"/>"#).unwrap();
assert_eq!(data, Node::Newtype(NewtypeContent { value: true }));
}
}
mod struct_ {
use super::*;
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn elements() {
let data: Node = from_str(
r#"<root><tag>Struct</tag><float>42</float><string>answer</string></root>"#,
)
.unwrap();
assert_eq!(
data,
Node::Struct {
float: "42".into(),
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Node =
from_str(r#"<root tag="Struct" float="42" string="answer"/>"#).unwrap();
assert_eq!(
data,
Node::Struct {
float: "42".into(),
string: "answer".into()
}
);
}
}
mod nested_struct {
use super::*;
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn elements() {
let data: Node = from_str(
r#"<root><tag>Holder</tag><string>answer</string><nested><float>42</float></nested></root>"#
).unwrap();
assert_eq!(
data,
Node::Holder {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Node = from_str(
r#"<root tag="Holder" string="answer"><nested float="42"/></root>"#,
)
.unwrap();
assert_eq!(
data,
Node::Holder {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
}
mod flatten_struct {
use super::*;
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn elements() {
let data: Node = from_str(
r#"<root><tag>Flatten</tag><float>42</float><string>answer</string></root>"#
).unwrap();
assert_eq!(
data,
Node::Flatten {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Node =
from_str(r#"<root tag="Flatten" float="42" string="answer"/>"#).unwrap();
assert_eq!(
data,
Node::Flatten {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
}
}
mod adjacently_tagged {
use super::*;
#[derive(Debug, Deserialize, PartialEq)]
#[serde(tag = "tag", content = "content")]
enum Node {
Unit,
Newtype(bool),
Struct {
float: f64,
string: String,
},
Holder {
nested: Nested,
string: String,
},
Flatten {
#[serde(flatten)]
nested: Nested,
string: String,
},
}
#[derive(Debug, Deserialize, PartialEq)]
struct Nested {
float: String,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(tag = "tag", content = "content")]
enum Workaround {
Tuple(f64, String),
}
mod unit {
use super::*;
#[test]
fn elements() {
let data: Node = from_str(r#"<root><tag>Unit</tag></root>"#).unwrap();
assert_eq!(data, Node::Unit);
}
#[test]
fn attributes() {
let data: Node = from_str(r#"<root tag="Unit"/>"#).unwrap();
assert_eq!(data, Node::Unit);
}
}
mod newtype {
use super::*;
#[test]
fn elements() {
let data: Node =
from_str(r#"<root><tag>Newtype</tag><content>true</content></root>"#)
.unwrap();
assert_eq!(data, Node::Newtype(true));
}
#[test]
fn attributes() {
let data: Node = from_str(r#"<root tag="Newtype" content="true"/>"#).unwrap();
assert_eq!(data, Node::Newtype(true));
}
}
mod tuple_struct {
use super::*;
#[test]
fn elements() {
let data: Workaround = from_str(
r#"<root><tag>Tuple</tag><content>42</content><content>answer</content></root>"#
).unwrap();
assert_eq!(data, Workaround::Tuple(42.0, "answer".into()));
}
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn attributes() {
let data: Workaround = from_str(
r#"<root tag="Tuple" content="42"><content>answer</content></root>"#,
)
.unwrap();
assert_eq!(data, Workaround::Tuple(42.0, "answer".into()));
}
}
mod struct_ {
use super::*;
#[test]
fn elements() {
let data: Node = from_str(
r#"<root><tag>Struct</tag><content><float>42</float><string>answer</string></content></root>"#
).unwrap();
assert_eq!(
data,
Node::Struct {
float: 42.0,
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Node = from_str(
r#"<root tag="Struct"><content float="42" string="answer"/></root>"#,
)
.unwrap();
assert_eq!(
data,
Node::Struct {
float: 42.0,
string: "answer".into()
}
);
}
}
mod nested_struct {
use super::*;
#[test]
fn elements() {
let data: Node = from_str(
r#"<root>
<tag>Holder</tag>
<content>
<string>answer</string>
<nested>
<float>42</float>
</nested>
</content>
</root>"#,
)
.unwrap();
assert_eq!(
data,
Node::Holder {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Node = from_str(
r#"<root tag="Holder"><content string="answer"><nested float="42"/></content></root>"#
).unwrap();
assert_eq!(
data,
Node::Holder {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
}
mod flatten_struct {
use super::*;
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn elements() {
let data: Node = from_str(
r#"<root><tag>Flatten</tag><content><float>42</float><string>answer</string></content></root>"#
).unwrap();
assert_eq!(
data,
Node::Flatten {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Node = from_str(
r#"<root tag="Flatten"><content float="42" string="answer"/></root>"#,
)
.unwrap();
assert_eq!(
data,
Node::Flatten {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
}
}
mod untagged {
use super::*;
#[derive(Debug, Deserialize, PartialEq)]
#[serde(untagged)]
enum Node {
Unit,
Newtype(bool),
Struct {
float: f64,
string: String,
},
Holder {
nested: Nested,
string: String,
},
Flatten {
#[serde(flatten)]
nested: Nested,
string2: String,
},
}
#[derive(Debug, Deserialize, PartialEq)]
struct Nested {
float: String,
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(untagged)]
enum Workaround {
Tuple(f64, String),
}
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn unit() {
let data: Node = from_str("").unwrap();
assert_eq!(data, Node::Unit);
}
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn newtype() {
let data: Node = from_str("true").unwrap();
assert_eq!(data, Node::Newtype(true));
}
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn tuple_struct() {
let data: Workaround = from_str("<root>42</root><root>answer</root>").unwrap();
assert_eq!(data, Workaround::Tuple(42.0, "answer".into()));
}
mod struct_ {
use super::*;
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn elements() {
let data: Node =
from_str(r#"<root><float>42</float><string>answer</string></root>"#)
.unwrap();
assert_eq!(
data,
Node::Struct {
float: 42.0,
string: "answer".into()
}
);
}
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn attributes() {
let data: Node = from_str(r#"<root float="42" string="answer"/>"#).unwrap();
assert_eq!(
data,
Node::Struct {
float: 42.0,
string: "answer".into()
}
);
}
}
mod nested_struct {
use super::*;
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn elements() {
let data: Node = from_str(
r#"<root><string>answer</string><nested><float>42</float></nested></root>"#,
)
.unwrap();
assert_eq!(
data,
Node::Holder {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Node =
from_str(r#"<root string="answer"><nested float="42"/></root>"#).unwrap();
assert_eq!(
data,
Node::Holder {
nested: Nested { float: "42".into() },
string: "answer".into()
}
);
}
}
mod flatten_struct {
use super::*;
#[test]
#[ignore = "Prime cause: deserialize_any under the hood + https://github.com/serde-rs/serde/issues/1183"]
fn elements() {
let data: Node =
from_str(r#"<root><float>42</float><string2>answer</string2></root>"#)
.unwrap();
assert_eq!(
data,
Node::Flatten {
nested: Nested { float: "42".into() },
string2: "answer".into()
}
);
}
#[test]
fn attributes() {
let data: Node = from_str(r#"<root float="42" string2="answer"/>"#).unwrap();
assert_eq!(
data,
Node::Flatten {
nested: Nested { float: "42".into() },
string2: "answer".into()
}
);
}
}
}
}
}