use std::borrow::Cow;
use serde::{Deserialize, Serialize};
#[non_exhaustive]
#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Xml {
#[serde(skip_serializing_if = "Option::is_none")]
pub node_type: Option<XmlNodeType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<Cow<'static, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub namespace: Option<Cow<'static, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prefix: Option<Cow<'static, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attribute: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wrapped: Option<bool>,
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum XmlNodeType {
Element,
Attribute,
Text,
Cdata,
None,
}
impl Xml {
#[must_use]
pub fn new() -> Self {
Self {
..Default::default()
}
}
}
impl Xml {
#[must_use]
pub fn node_type(mut self, node_type: XmlNodeType) -> Self {
self.node_type = Some(node_type);
self
}
#[must_use]
pub fn name<S: Into<Cow<'static, str>>>(mut self, name: S) -> Self {
self.name = Some(name.into());
self
}
#[must_use]
pub fn namespace<S: Into<Cow<'static, str>>>(mut self, namespace: S) -> Self {
self.namespace = Some(namespace.into());
self
}
#[must_use]
pub fn prefix<S: Into<Cow<'static, str>>>(mut self, prefix: S) -> Self {
self.prefix = Some(prefix.into());
self
}
#[must_use]
pub fn attribute(mut self, attribute: bool) -> Self {
self.attribute = Some(attribute);
self
}
#[must_use]
pub fn wrapped(mut self, wrapped: bool) -> Self {
self.wrapped = Some(wrapped);
self
}
}
#[cfg(test)]
mod tests {
use super::{Xml, XmlNodeType};
#[test]
fn xml_new() {
let mut xml = Xml::new();
assert!(xml.name.is_none());
assert!(xml.namespace.is_none());
assert!(xml.prefix.is_none());
assert!(xml.attribute.is_none());
assert!(xml.wrapped.is_none());
xml = xml.name("name");
assert!(xml.name.is_some());
xml = xml.namespace("namespace");
assert!(xml.namespace.is_some());
xml = xml.prefix("prefix");
assert!(xml.prefix.is_some());
xml = xml.attribute(true);
assert!(xml.attribute.is_some());
xml = xml.wrapped(true);
assert!(xml.wrapped.is_some());
}
#[test]
fn xml_node_type_round_trips() {
for (node_type, rendered) in [
(XmlNodeType::Element, "element"),
(XmlNodeType::Attribute, "attribute"),
(XmlNodeType::Text, "text"),
(XmlNodeType::Cdata, "cdata"),
(XmlNodeType::None, "none"),
] {
let xml = Xml::new().node_type(node_type);
let value = serde_json::to_value(&xml).expect("serialize");
assert_eq!(value, serde_json::json!({ "nodeType": rendered }));
let parsed: Xml = serde_json::from_value(value).expect("deserialize");
assert_eq!(parsed.node_type, Some(node_type));
}
}
#[test]
fn xml_without_node_type_is_unchanged() {
let xml = Xml::new().name("pet").wrapped(true);
assert_eq!(
serde_json::to_value(&xml).expect("serialize"),
serde_json::json!({ "name": "pet", "wrapped": true })
);
}
}