use std::borrow::Cow;
use serde::de::{self, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess, VariantAccess, Visitor};
use sup_xml_core::{EventInto, XmlReader};
use super::{DeError, DeOptions};
#[derive(Debug)]
enum Pending<'src> {
Start { name: Cow<'src, str>, attrs: Vec<(Cow<'src, str>, Cow<'src, str>)> },
End,
Text(Cow<'src, str>),
CData(Cow<'src, str>),
Eof,
}
pub struct XmlDeserializer<'de> {
reader: XmlReader<'de>,
opts: DeOptions,
lookahead: Option<Pending<'de>>,
attr_buf: Vec<sup_xml_core::Attr<'de>>,
}
impl<'de> XmlDeserializer<'de> {
pub fn from_str(input: &'de str) -> Self {
Self::from_str_opts(input, DeOptions::default())
}
pub fn from_str_opts(input: &'de str, opts: DeOptions) -> Self {
let reader = XmlReader::from_str(input).with_options(opts.parse.clone());
Self {
reader,
opts,
lookahead: None,
attr_buf: Vec::new(),
}
}
fn pull(&mut self) -> Result<Pending<'de>, DeError> {
loop {
let ev = self.reader.next_into(&mut self.attr_buf)?;
match ev {
EventInto::Comment(_) | EventInto::Pi { .. } => continue,
EventInto::StartElement { name } => {
let attrs = self.attr_buf.drain(..)
.map(|a| (Cow::Borrowed(a.name), a.value))
.collect();
return Ok(Pending::Start { name, attrs });
}
EventInto::EndElement { .. } => return Ok(Pending::End),
EventInto::Text(t) => return Ok(Pending::Text(t)),
EventInto::CData(s) => return Ok(Pending::CData(s)),
EventInto::EntityRef { name } => {
return Err(DeError::msg(format!(
"typed deserialization requires `resolve_entities: true`; \
encountered unresolved entity reference `&{name};`"
)));
}
EventInto::Eof => return Ok(Pending::Eof),
}
}
}
fn peek(&mut self) -> Result<&Pending<'de>, DeError> {
if self.lookahead.is_none() {
let p = self.pull()?;
self.lookahead = Some(p);
}
Ok(self.lookahead.as_ref().unwrap())
}
fn advance(&mut self) -> Result<Pending<'de>, DeError> {
if let Some(p) = self.lookahead.take() {
return Ok(p);
}
self.pull()
}
fn skip_leading_ws(&mut self) -> Result<(), DeError> {
loop {
match self.peek()? {
Pending::Text(t) if t.chars().all(char::is_whitespace) => {
let _ = self.advance()?;
}
_ => return Ok(()),
}
}
}
fn read_text_body(&mut self) -> Result<String, DeError> {
let mut out = String::new();
loop {
match self.advance()? {
Pending::Text(t) | Pending::CData(t) => out.push_str(&t),
Pending::End => return Ok(out),
Pending::Start { name, .. } => return Err(DeError::msg(format!(
"expected scalar content but found nested element <{}>", name
))),
Pending::Eof => return Err(DeError::msg(
"unexpected EOF while reading element text content"
)),
}
}
}
fn skip_body(&mut self) -> Result<(), DeError> {
let mut depth = 1usize;
while depth > 0 {
match self.advance()? {
Pending::Start { .. } => depth += 1,
Pending::End => depth -= 1,
Pending::Eof => return Err(DeError::msg("unexpected EOF in skip_body")),
_ => {}
}
}
Ok(())
}
fn scalar_text(&mut self) -> Result<String, DeError> {
self.skip_leading_ws()?;
match self.advance()? {
Pending::Start { .. } => self.read_text_body(),
Pending::Text(t) | Pending::CData(t) => Ok(t.into_owned()),
other => Err(DeError::msg(format!(
"expected scalar element, got {other:?}"
))),
}
}
}
macro_rules! deserialize_int {
($($method:ident => $visit:ident => $ty:ty),* $(,)?) => {$(
fn $method<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
let s = self.scalar_text()?;
let n: $ty = s.trim().parse()
.map_err(|e| DeError::msg(format!("invalid {}: {e}", stringify!($ty))))?;
v.$visit(n)
}
)*};
}
impl<'de, 'a> de::Deserializer<'de> for &'a mut XmlDeserializer<'de> {
type Error = DeError;
fn deserialize_any<V: Visitor<'de>>(self, _v: V) -> Result<V::Value, DeError> {
Err(DeError::msg(
"deserialize_any is not supported — XML lacks the type metadata for it; \
use a typed Deserialize impl instead",
))
}
fn deserialize_str<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
self.deserialize_string(v)
}
fn deserialize_string<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
let s = self.scalar_text()?;
v.visit_string(s)
}
deserialize_int! {
deserialize_i8 => visit_i8 => i8,
deserialize_i16 => visit_i16 => i16,
deserialize_i32 => visit_i32 => i32,
deserialize_i64 => visit_i64 => i64,
deserialize_i128 => visit_i128 => i128,
deserialize_u8 => visit_u8 => u8,
deserialize_u16 => visit_u16 => u16,
deserialize_u32 => visit_u32 => u32,
deserialize_u64 => visit_u64 => u64,
deserialize_u128 => visit_u128 => u128,
deserialize_f32 => visit_f32 => f32,
deserialize_f64 => visit_f64 => f64,
}
fn deserialize_bool<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
let s = self.scalar_text()?;
match s.trim() {
"true" | "1" => v.visit_bool(true),
"false" | "0" => v.visit_bool(false),
other => Err(DeError::msg(format!("invalid bool: {other:?}"))),
}
}
fn deserialize_char<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
let s = self.scalar_text()?;
let mut it = s.chars();
match (it.next(), it.next()) {
(Some(c), None) => v.visit_char(c),
_ => Err(DeError::msg(format!("expected single char, got {s:?}"))),
}
}
fn deserialize_bytes<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
let s = self.scalar_text()?;
v.visit_byte_buf(s.into_bytes())
}
fn deserialize_byte_buf<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
self.deserialize_bytes(v)
}
fn deserialize_unit<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
self.skip_leading_ws()?;
match self.advance()? {
Pending::Start { .. } => { self.skip_body()?; v.visit_unit() }
Pending::Eof => v.visit_unit(),
other => Err(DeError::msg(format!("expected element for unit, got {other:?}"))),
}
}
fn deserialize_unit_struct<V: Visitor<'de>>(self, _name: &'static str, v: V)
-> Result<V::Value, DeError>
{
self.deserialize_unit(v)
}
fn deserialize_newtype_struct<V: Visitor<'de>>(self, _name: &'static str, v: V)
-> Result<V::Value, DeError>
{
v.visit_newtype_struct(self)
}
fn deserialize_ignored_any<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
self.skip_leading_ws()?;
if let Pending::Start { .. } = self.peek()? {
let _ = self.advance()?;
self.skip_body()?;
}
v.visit_unit()
}
fn deserialize_struct<V: Visitor<'de>>(
self,
_name: &'static str,
fields: &'static [&'static str],
v: V,
) -> Result<V::Value, DeError> {
self.skip_leading_ws()?;
let attrs = match self.advance()? {
Pending::Start { attrs, .. } => attrs,
other => return Err(DeError::msg(format!(
"expected element start for struct, got {other:?}"
))),
};
let map = StructMap::new(self, attrs, fields);
v.visit_map(map)
}
fn deserialize_seq<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
self.skip_leading_ws()?;
let tag: Option<String> = match self.peek()? {
Pending::Start { name, .. } => Some(name.clone().into_owned()),
_ => None,
};
v.visit_seq(ElementSeq { de: self, tag })
}
fn deserialize_tuple<V: Visitor<'de>>(self, _len: usize, v: V) -> Result<V::Value, DeError> {
self.deserialize_seq(v)
}
fn deserialize_tuple_struct<V: Visitor<'de>>(
self,
_name: &'static str,
_len: usize,
v: V,
) -> Result<V::Value, DeError> {
self.deserialize_seq(v)
}
fn deserialize_map<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
self.skip_leading_ws()?;
let attrs = match self.advance()? {
Pending::Start { attrs, .. } => attrs,
other => return Err(DeError::msg(format!(
"expected element start for map, got {other:?}"
))),
};
v.visit_map(StructMap::new(self, attrs, &[]))
}
fn deserialize_option<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
self.skip_leading_ws()?;
if self.opts.honor_xsi_nil {
let nil = matches!(self.peek()?, Pending::Start { attrs, .. } if is_xsi_nil(attrs));
if nil {
let _ = self.advance()?;
self.skip_body()?;
return v.visit_none();
}
}
v.visit_some(self)
}
fn deserialize_enum<V: Visitor<'de>>(
self,
_name: &'static str,
_variants: &'static [&'static str],
v: V,
) -> Result<V::Value, DeError> {
self.skip_leading_ws()?;
let variant = match self.peek()? {
Pending::Start { name, .. } => name.clone().into_owned(),
other => return Err(DeError::msg(format!(
"expected element start for enum, got {other:?}"
))),
};
v.visit_enum(EnumElement { de: self, variant })
}
fn deserialize_identifier<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
self.deserialize_str(v)
}
}
struct ElementSeq<'a, 'de> {
de: &'a mut XmlDeserializer<'de>,
tag: Option<String>,
}
impl<'de> SeqAccess<'de> for ElementSeq<'_, 'de> {
type Error = DeError;
fn next_element_seed<T: DeserializeSeed<'de>>(&mut self, seed: T)
-> Result<Option<T::Value>, DeError>
{
let tag = match &self.tag {
Some(t) => t.as_str(),
None => return Ok(None),
};
loop {
match self.de.peek()? {
Pending::Text(t) if t.chars().all(char::is_whitespace) => {
let _ = self.de.advance()?;
}
Pending::Start { name, .. } if name.as_ref() == tag => {
return seed.deserialize(&mut *self.de).map(Some);
}
_ => return Ok(None),
}
}
}
}
struct EnumElement<'a, 'de> {
de: &'a mut XmlDeserializer<'de>,
variant: String,
}
impl<'de> EnumAccess<'de> for EnumElement<'_, 'de> {
type Error = DeError;
type Variant = Self;
fn variant_seed<V: DeserializeSeed<'de>>(self, seed: V)
-> Result<(V::Value, Self::Variant), DeError>
{
let de: serde::de::value::StringDeserializer<DeError> =
self.variant.clone().into_deserializer();
let value = seed.deserialize(de)?;
Ok((value, self))
}
}
impl<'de> VariantAccess<'de> for EnumElement<'_, 'de> {
type Error = DeError;
fn unit_variant(self) -> Result<(), DeError> {
match self.de.advance()? {
Pending::Start { .. } => self.de.skip_body(),
other => Err(DeError::msg(format!(
"expected element for unit variant, got {other:?}"
))),
}
}
fn newtype_variant_seed<T: DeserializeSeed<'de>>(self, seed: T)
-> Result<T::Value, DeError>
{
seed.deserialize(&mut *self.de)
}
fn tuple_variant<V: Visitor<'de>>(self, _len: usize, _v: V) -> Result<V::Value, DeError> {
Err(DeError::msg("tuple variants are not supported in v1"))
}
fn struct_variant<V: Visitor<'de>>(
self,
fields: &'static [&'static str],
v: V,
) -> Result<V::Value, DeError> {
de::Deserializer::deserialize_struct(&mut *self.de, "", fields, v)
}
}
struct StructMap<'a, 'de> {
de: &'a mut XmlDeserializer<'de>,
attrs: std::vec::IntoIter<(Cow<'de, str>, Cow<'de, str>)>,
pending_attr_value: Option<Cow<'de, str>>,
in_body: bool,
body_done: bool,
text_buf: String,
text_yielded: bool,
text_value_pending: bool,
value_pending: bool,
fields: &'static [&'static str],
has_value_field: bool,
attr_prefix: char,
text_field_name: &'static str,
value_field_name: &'static str,
}
impl<'a, 'de> StructMap<'a, 'de> {
fn new(
de: &'a mut XmlDeserializer<'de>,
attrs: Vec<(Cow<'de, str>, Cow<'de, str>)>,
fields: &'static [&'static str],
) -> Self {
let attr_prefix = de.opts.attribute_prefix;
let text_field_name = de.opts.text_field_name;
let value_field_name = de.opts.value_field_name;
let has_value_field = fields.contains(&value_field_name);
Self {
de,
attrs: attrs.into_iter(),
pending_attr_value: None,
in_body: false,
body_done: false,
text_buf: String::new(),
text_yielded: false,
text_value_pending: false,
value_pending: false,
fields,
has_value_field,
attr_prefix,
text_field_name,
value_field_name,
}
}
fn is_named_field(&self, name: &str) -> bool {
self.fields.iter().any(|f| *f == name)
}
}
impl<'de> MapAccess<'de> for StructMap<'_, 'de> {
type Error = DeError;
fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K)
-> Result<Option<K::Value>, DeError>
{
if !self.in_body {
if let Some((name, value)) = self.attrs.next() {
self.pending_attr_value = Some(value);
let key = format!("{}{}", self.attr_prefix, name);
return seed.deserialize(key.into_deserializer()).map(Some);
}
self.in_body = true;
}
if !self.body_done {
loop {
let peek_kind = match self.de.peek()? {
Pending::End => PeekKind::End,
Pending::Eof => PeekKind::Eof,
Pending::Text(_) | Pending::CData(_) => PeekKind::Text,
Pending::Start { name, .. } => PeekKind::Start(name.clone().into_owned()),
};
match peek_kind {
PeekKind::End => {
let _ = self.de.advance()?;
self.body_done = true;
break;
}
PeekKind::Eof => {
return Err(DeError::msg("unexpected EOF inside struct"));
}
PeekKind::Text => {
match self.de.advance()? {
Pending::Text(t) | Pending::CData(t) => self.text_buf.push_str(&t),
_ => unreachable!(),
}
}
PeekKind::Start(name) => {
if self.has_value_field && !self.is_named_field(&name) {
self.value_pending = true;
return seed
.deserialize(self.value_field_name.into_deserializer())
.map(Some);
}
return seed.deserialize(name.into_deserializer()).map(Some);
}
}
}
}
if !self.text_yielded && !self.text_buf.trim().is_empty() {
self.text_yielded = true;
self.text_value_pending = true;
return seed.deserialize(self.text_field_name.into_deserializer()).map(Some);
}
Ok(None)
}
fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V)
-> Result<V::Value, DeError>
{
if let Some(val) = self.pending_attr_value.take() {
return seed.deserialize(ScalarStrDeserializer { value: val });
}
if self.text_value_pending {
self.text_value_pending = false;
let text = std::mem::take(&mut self.text_buf);
return seed.deserialize(ScalarStrDeserializer { value: Cow::Owned(text) });
}
if self.value_pending {
self.value_pending = false;
return seed.deserialize(ValueSeqDeserializer { de: &mut *self.de });
}
seed.deserialize(&mut *self.de)
}
}
enum PeekKind {
Start(String),
End,
Text,
Eof,
}
struct ValueSeqDeserializer<'a, 'de> {
de: &'a mut XmlDeserializer<'de>,
}
impl<'de> de::Deserializer<'de> for ValueSeqDeserializer<'_, 'de> {
type Error = DeError;
fn deserialize_any<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
self.deserialize_seq(v)
}
fn deserialize_seq<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
v.visit_seq(AnyElementSeq { de: self.de })
}
fn deserialize_tuple<V: Visitor<'de>>(self, _len: usize, v: V) -> Result<V::Value, DeError> {
self.deserialize_seq(v)
}
fn deserialize_tuple_struct<V: Visitor<'de>>(
self,
_name: &'static str,
_len: usize,
v: V,
) -> Result<V::Value, DeError> {
self.deserialize_seq(v)
}
fn deserialize_newtype_struct<V: Visitor<'de>>(self, _name: &'static str, v: V)
-> Result<V::Value, DeError>
{
v.visit_newtype_struct(self)
}
fn deserialize_option<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
v.visit_some(self)
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64
char str string bytes byte_buf unit unit_struct
map struct enum identifier ignored_any
}
}
struct AnyElementSeq<'a, 'de> {
de: &'a mut XmlDeserializer<'de>,
}
impl<'de> SeqAccess<'de> for AnyElementSeq<'_, 'de> {
type Error = DeError;
fn next_element_seed<T: DeserializeSeed<'de>>(&mut self, seed: T)
-> Result<Option<T::Value>, DeError>
{
loop {
match self.de.peek()? {
Pending::End | Pending::Eof => return Ok(None),
Pending::Text(t) | Pending::CData(t) if t.chars().all(char::is_whitespace) => {
let _ = self.de.advance()?;
}
Pending::Text(_) | Pending::CData(_) => {
let _ = self.de.advance()?;
}
Pending::Start { .. } => {
return seed.deserialize(&mut *self.de).map(Some);
}
}
}
}
}
fn is_xsi_nil(attrs: &[(Cow<'_, str>, Cow<'_, str>)]) -> bool {
attrs.iter().any(|(n, v)|
n.as_ref() == "xsi:nil" && matches!(v.trim(), "true" | "1")
)
}
struct ScalarStrDeserializer<'de> {
value: Cow<'de, str>,
}
macro_rules! sv_int {
($($method:ident => $visit:ident => $ty:ty),* $(,)?) => {$(
fn $method<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
let n: $ty = self.value.trim().parse()
.map_err(|e| DeError::msg(format!("invalid {}: {e}", stringify!($ty))))?;
v.$visit(n)
}
)*};
}
impl<'de> de::Deserializer<'de> for ScalarStrDeserializer<'de> {
type Error = DeError;
fn deserialize_any<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
match self.value {
Cow::Borrowed(s) => v.visit_borrowed_str(s),
Cow::Owned(s) => v.visit_string(s),
}
}
fn deserialize_str<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
match self.value {
Cow::Borrowed(s) => v.visit_borrowed_str(s),
Cow::Owned(s) => v.visit_string(s),
}
}
fn deserialize_string<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
self.deserialize_str(v)
}
fn deserialize_bool<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
match self.value.trim() {
"true" | "1" => v.visit_bool(true),
"false" | "0" => v.visit_bool(false),
other => Err(DeError::msg(format!("invalid bool: {other:?}"))),
}
}
fn deserialize_char<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
let mut it = self.value.chars();
match (it.next(), it.next()) {
(Some(c), None) => v.visit_char(c),
_ => Err(DeError::msg(format!("expected single char, got {:?}", self.value))),
}
}
sv_int! {
deserialize_i8 => visit_i8 => i8,
deserialize_i16 => visit_i16 => i16,
deserialize_i32 => visit_i32 => i32,
deserialize_i64 => visit_i64 => i64,
deserialize_i128 => visit_i128 => i128,
deserialize_u8 => visit_u8 => u8,
deserialize_u16 => visit_u16 => u16,
deserialize_u32 => visit_u32 => u32,
deserialize_u64 => visit_u64 => u64,
deserialize_u128 => visit_u128 => u128,
deserialize_f32 => visit_f32 => f32,
deserialize_f64 => visit_f64 => f64,
}
fn deserialize_bytes<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
match self.value {
Cow::Borrowed(s) => v.visit_borrowed_bytes(s.as_bytes()),
Cow::Owned(s) => v.visit_byte_buf(s.into_bytes()),
}
}
fn deserialize_byte_buf<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
self.deserialize_bytes(v)
}
fn deserialize_option<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
v.visit_some(self)
}
fn deserialize_unit<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
v.visit_unit()
}
fn deserialize_unit_struct<V: Visitor<'de>>(self, _name: &'static str, v: V)
-> Result<V::Value, DeError>
{
v.visit_unit()
}
fn deserialize_newtype_struct<V: Visitor<'de>>(self, _name: &'static str, v: V)
-> Result<V::Value, DeError>
{
v.visit_newtype_struct(self)
}
fn deserialize_seq<V: Visitor<'de>>(self, _v: V) -> Result<V::Value, DeError> {
Err(DeError::msg("cannot deserialize attribute/text value as a seq"))
}
fn deserialize_tuple<V: Visitor<'de>>(self, _len: usize, _v: V) -> Result<V::Value, DeError> {
Err(DeError::msg("cannot deserialize attribute/text value as a tuple"))
}
fn deserialize_tuple_struct<V: Visitor<'de>>(self, _n: &'static str, _l: usize, _v: V)
-> Result<V::Value, DeError>
{
Err(DeError::msg("cannot deserialize attribute/text value as a tuple struct"))
}
fn deserialize_map<V: Visitor<'de>>(self, _v: V) -> Result<V::Value, DeError> {
Err(DeError::msg("cannot deserialize attribute/text value as a map"))
}
fn deserialize_struct<V: Visitor<'de>>(
self,
_name: &'static str,
_fields: &'static [&'static str],
_v: V,
) -> Result<V::Value, DeError> {
Err(DeError::msg("cannot deserialize attribute/text value as a struct"))
}
fn deserialize_enum<V: Visitor<'de>>(
self,
_name: &'static str,
_variants: &'static [&'static str],
v: V,
) -> Result<V::Value, DeError> {
v.visit_enum(self.value.into_owned().into_deserializer())
}
fn deserialize_identifier<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
self.deserialize_str(v)
}
fn deserialize_ignored_any<V: Visitor<'de>>(self, v: V) -> Result<V::Value, DeError> {
v.visit_unit()
}
}