Revision control
Copy as Markdown
Other Tools
use crate::de::str2bool;↩
use crate::encoding::Decoder;↩
use crate::errors::serialize::DeError;↩
use crate::name::QName;↩
use crate::utils::CowRef;↩
use serde::de::{DeserializeSeed, Deserializer, EnumAccess, VariantAccess, Visitor};↩
use serde::{forward_to_deserialize_any, serde_if_integer128};↩
use std::borrow::Cow;↩
↩
macro_rules! deserialize_num {↩
($method:ident, $visit:ident) => {↩
fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>↩
where↩
V: Visitor<'de>,↩
{↩
visitor.$visit(self.name.parse()?)↩
}↩
};↩
}↩
↩
/// Decodes raw bytes using the deserializer encoding.↩
/// The method will borrow if encoding is UTF-8 compatible and `name` contains↩
/// only UTF-8 compatible characters (usually only ASCII characters).↩
#[inline]↩
fn decode_name<'n>(name: QName<'n>, decoder: Decoder) -> Result<Cow<'n, str>, DeError> {↩
let local = name.local_name();↩
Ok(decoder.decode(local.into_inner())?)↩
}↩
↩
/// A deserializer for xml names of elements and attributes.↩
///↩
/// Used for deserializing values from:↩
/// - attribute names (`<... name="..." ...>`)↩
/// - element names (`<name>...</name>`)↩
///↩
/// Converts a name to an identifier string using the following rules:↩
///↩
/// - if it is an [`attribute`] name, put `@` in front of the identifier↩
/// - if it is a namespace binding (`xmlns` or `xmlns:xxx`) put the decoded name↩
/// to the identifier↩
/// - put the decoded [`local_name()`] of a name to the identifier↩
///↩
/// The final identifier looks like `[@]local_name`, or `@xmlns`, or `@xmlns:binding`↩
/// (where `[]` means optional element).↩
///↩
/// The deserializer also supports deserializing names as other primitive types:↩
/// - numbers↩
/// - booleans↩
/// - unit (`()`) and unit structs↩
/// - unit variants of the enumerations↩
///↩
/// Because `serde` does not define on which side type conversion should be↩
/// performed, and because [`Deserialize`] implementation for that primitives↩
/// in serde does not accept strings, the deserializer will perform conversion↩
/// by itself.↩
///↩
/// The deserializer is able to deserialize unit and unit structs, but any name↩
/// will be converted to the same unit instance. This is asymmetry with a serializer,↩
/// which not able to serialize those types, because empty names are impossible↩
/// in XML.↩
///↩
/// `deserialize_any()` returns the same result as `deserialize_identifier()`.↩
///↩
/// # Lifetimes↩
///↩
/// - `'i`: lifetime of the data that the deserializer borrows from the parsed input↩
/// - `'d`: lifetime of a deserializer that holds a buffer with content of events↩
///↩
/// [`attribute`]: Self::from_attr↩
/// [`local_name()`]: QName::local_name↩
/// [`Deserialize`]: serde::Deserialize↩
pub struct QNameDeserializer<'i, 'd> {↩
name: CowRef<'i, 'd, str>,↩
}↩
↩
impl<'i, 'd> QNameDeserializer<'i, 'd> {↩
/// Creates deserializer from name of an attribute↩
pub fn from_attr(name: QName<'d>, decoder: Decoder) -> Result<Self, DeError> {↩
// Namespace bindings (xmlns:xxx) map to `@xmlns:xxx` instead of `@xxx`↩
let field = if name.as_namespace_binding().is_some() {↩
decoder.decode(name.into_inner())?↩
} else {↩
decode_name(name, decoder)?↩
};↩
↩
Ok(Self {↩
name: CowRef::Owned(format!("@{field}")),↩
})↩
}↩
↩
/// Creates deserializer from name of an element↩
pub fn from_elem(name: CowRef<'i, 'd, [u8]>, decoder: Decoder) -> Result<Self, DeError> {↩
let local = match name {↩
CowRef::Input(borrowed) => match decode_name(QName(borrowed), decoder)? {↩
Cow::Borrowed(borrowed) => CowRef::Input(borrowed),↩
Cow::Owned(owned) => CowRef::Owned(owned),↩
},↩
CowRef::Slice(borrowed) => match decode_name(QName(borrowed), decoder)? {↩
Cow::Borrowed(borrowed) => CowRef::Slice(borrowed),↩
Cow::Owned(owned) => CowRef::Owned(owned),↩
},↩
CowRef::Owned(owned) => match decode_name(QName(&owned), decoder)? {↩
// SAFETY: Because result is borrowed, no changes was done↩
// and we can safely unwrap here↩
Cow::Borrowed(_) => CowRef::Owned(String::from_utf8(owned).unwrap()),↩
Cow::Owned(owned) => CowRef::Owned(owned),↩
},↩
};↩
↩
Ok(Self { name: local })↩
}↩
}↩
↩
impl<'de, 'd> Deserializer<'de> for QNameDeserializer<'de, 'd> {↩
type Error = DeError;↩
↩
forward_to_deserialize_any! {↩
char str string↩
bytes byte_buf↩
seq tuple tuple_struct↩
map struct↩
ignored_any↩
}↩
↩
/// valid boolean representations are only `"true"`, `"false"`, `"1"`,↩
/// and `"0"`. But this method also handles following:↩
///↩
/// |`bool` |XML content↩
/// |-------|-------------------------------------------------------------↩
/// |`true` |`"True"`, `"TRUE"`, `"t"`, `"Yes"`, `"YES"`, `"yes"`, `"y"`↩
/// |`false`|`"False"`, `"FALSE"`, `"f"`, `"No"`, `"NO"`, `"no"`, `"n"`↩
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>↩
where↩
V: Visitor<'de>,↩
{↩
str2bool(self.name.as_ref(), 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);↩
↩
/// Calls [`Visitor::visit_unit`]↩
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>↩
where↩
V: Visitor<'de>,↩
{↩
visitor.visit_unit()↩
}↩
↩
/// Forwards deserialization to the [`Self::deserialize_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)↩
}↩
↩
/// Forwards deserialization to the [`Self::deserialize_identifier`]↩
#[inline]↩
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>↩
where↩
V: Visitor<'de>,↩
{↩
self.deserialize_identifier(visitor)↩
}↩
↩
/// If `name` is an empty string then calls [`Visitor::visit_none`],↩
/// otherwise calls [`Visitor::visit_some`] with itself↩
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>↩
where↩
V: Visitor<'de>,↩
{↩
if self.name.is_empty() {↩
visitor.visit_none()↩
} else {↩
visitor.visit_some(self)↩
}↩
}↩
↩
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)↩
}↩
↩
/// Calls a [`Visitor::visit_str`] if [`name`] contains only UTF-8↩
/// compatible encoded characters and represents an element name and↩
/// a [`Visitor::visit_string`] in all other cases.↩
///↩
/// [`name`]: Self::name↩
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>↩
where↩
V: Visitor<'de>,↩
{↩
match self.name {↩
CowRef::Input(name) => visitor.visit_borrowed_str(name),↩
CowRef::Slice(name) => visitor.visit_str(name),↩
CowRef::Owned(name) => visitor.visit_string(name),↩
}↩
}↩
↩
fn deserialize_enum<V>(↩
self,↩
_name: &str,↩
_variants: &'static [&'static str],↩
visitor: V,↩
) -> Result<V::Value, Self::Error>↩
where↩
V: Visitor<'de>,↩
{↩
visitor.visit_enum(self)↩
}↩
}↩
↩
impl<'de, 'd> EnumAccess<'de> for QNameDeserializer<'de, 'd> {↩
type Error = DeError;↩
type Variant = QNameUnitOnly;↩
↩
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>↩
where↩
V: DeserializeSeed<'de>,↩
{↩
let name = seed.deserialize(self)?;↩
Ok((name, QNameUnitOnly))↩
}↩
}↩
↩
////////////////////////////////////////////////////////////////////////////////////////////////////↩
↩
/// Deserializer of variant data, that supports only unit variants.↩
/// Attempt to deserialize newtype, tuple or struct variant will return a↩
/// [`DeError::Unsupported`] error.↩
pub struct QNameUnitOnly;↩
impl<'de> VariantAccess<'de> for QNameUnitOnly {↩
type Error = DeError;↩
↩
#[inline]↩
fn unit_variant(self) -> Result<(), DeError> {↩
Ok(())↩
}↩
↩
fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, DeError>↩
where↩
T: DeserializeSeed<'de>,↩
{↩
Err(DeError::Unsupported(↩
"enum newtype variants are not supported as an XML names".into(),↩
))↩
}↩
↩
fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, DeError>↩
where↩
V: Visitor<'de>,↩
{↩
Err(DeError::Unsupported(↩
"enum tuple variants are not supported as an XML names".into(),↩
))↩
}↩
↩
fn struct_variant<V>(↩
self,↩
_fields: &'static [&'static str],↩
_visitor: V,↩
) -> Result<V::Value, DeError>↩
where↩
V: Visitor<'de>,↩
{↩
Err(DeError::Unsupported(↩
"enum struct variants are not supported as an XML names".into(),↩
))↩
}↩
}↩
↩
////////////////////////////////////////////////////////////////////////////////////////////////////↩
↩
#[cfg(test)]↩
mod tests {↩
use super::*;↩
use crate::se::key::QNameSerializer;↩
use crate::utils::{ByteBuf, Bytes};↩
use pretty_assertions::assert_eq;↩
use serde::de::IgnoredAny;↩
use serde::{Deserialize, Serialize};↩
use std::collections::HashMap;↩
↩
#[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 Struct {↩
key: String,↩
val: usize,↩
}↩
↩
#[derive(Debug, Deserialize, Serialize, PartialEq)]↩
enum Enum {↩
Unit,↩
#[serde(rename = "@Attr")]↩
Attr,↩
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↩
}↩
}↩
↩
/// Checks that given `$input` successfully deserializing into given `$result`↩
macro_rules! deserialized_to_only {↩
($name:ident: $type:ty = $input:literal => $result:expr) => {↩
#[test]↩
fn $name() {↩
let de = QNameDeserializer {↩
name: CowRef::Input($input),↩
};↩
let data: $type = Deserialize::deserialize(de).unwrap();↩
↩
assert_eq!(data, $result);↩
}↩
};↩
}↩
↩
/// Checks that given `$input` successfully deserializing into given `$result`↩
macro_rules! deserialized_to {↩
($name:ident: $type:ty = $input:literal => $result:expr) => {↩
#[test]↩
fn $name() {↩
let de = QNameDeserializer {↩
name: CowRef::Input($input),↩
};↩
let data: $type = Deserialize::deserialize(de).unwrap();↩
↩
assert_eq!(data, $result);↩
↩
// Roundtrip to ensure that serializer corresponds to deserializer↩
assert_eq!(↩
data.serialize(QNameSerializer {↩
writer: String::new()↩
})↩
.unwrap(),↩
$input↩
);↩
}↩
};↩
}↩
↩
/// Checks that attempt to deserialize given `$input` as a `$type` results to a↩
/// deserialization error `$kind` with `$reason`↩
macro_rules! err {↩
($name:ident: $type:ty = $input:literal => $kind:ident($reason:literal)) => {↩
#[test]↩
fn $name() {↩
let de = QNameDeserializer {↩
name: CowRef::Input($input),↩
};↩
let err = <$type as Deserialize>::deserialize(de).unwrap_err();↩
↩
match err {↩
DeError::$kind(e) => assert_eq!(e, $reason),↩
_ => panic!(↩
"Expected `{}({})`, found `{:?}`",↩
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');↩
err!(char_escaped: char = "<"↩
=> Custom("invalid value: string \"<\", expected a character"));↩
↩
deserialized_to!(string: String = "<escaped string" => "<escaped string");↩
deserialized_to!(borrowed_str: &str = "name" => "name");↩
↩
err!(byte_buf: ByteBuf = "<escaped string"↩
=> Custom("invalid type: string \"<escaped string\", expected byte data"));↩
err!(borrowed_bytes: Bytes = "name"↩
=> Custom("invalid type: string \"name\", expected borrowed bytes"));↩
↩
deserialized_to!(option_none: Option<String> = "" => None);↩
deserialized_to!(option_some: Option<String> = "name" => Some("name".into()));↩
↩
// Unit structs cannot be represented in some meaningful way, but it meaningful↩
// to use them as a placeholder when we want to deserialize _something_↩
deserialized_to_only!(unit: () = "anything" => ());↩
deserialized_to_only!(unit_struct: Unit = "anything" => Unit);↩
↩
deserialized_to!(newtype: Newtype = "<escaped string" => Newtype("<escaped string".into()));↩
↩
err!(seq: Vec<()> = "name"↩
=> Custom("invalid type: string \"name\", expected a sequence"));↩
err!(tuple: ((), ()) = "name"↩
=> Custom("invalid type: string \"name\", expected a tuple of size 2"));↩
err!(tuple_struct: Tuple = "name"↩
=> Custom("invalid type: string \"name\", expected tuple struct Tuple"));↩
↩
err!(map: HashMap<(), ()> = "name"↩
=> Custom("invalid type: string \"name\", expected a map"));↩
err!(struct_: Struct = "name"↩
=> Custom("invalid type: string \"name\", expected struct Struct"));↩
↩
deserialized_to!(enum_unit: Enum = "Unit" => Enum::Unit);↩
deserialized_to!(enum_unit_for_attr: Enum = "@Attr" => Enum::Attr);↩
err!(enum_newtype: Enum = "Newtype"↩
=> Unsupported("enum newtype variants are not supported as an XML names"));↩
err!(enum_tuple: Enum = "Tuple"↩
=> Unsupported("enum tuple variants are not supported as an XML names"));↩
err!(enum_struct: Enum = "Struct"↩
=> Unsupported("enum struct variants are not supported as an XML names"));↩
↩
// Field identifiers cannot be serialized, and IgnoredAny represented _something_↩
// which is not concrete↩
deserialized_to_only!(identifier: Id = "Field" => Id::Field);↩
deserialized_to_only!(ignored_any: Any = "any-name" => Any(IgnoredAny));↩
}↩