Separate Context out of Deserializer

This commit is contained in:
Dirkjan Ochtman 2022-09-06 12:26:23 +02:00
parent 2aa8a4b117
commit 3ad6917ba0
5 changed files with 290 additions and 395 deletions

View File

@ -115,7 +115,7 @@ impl Deserializer {
let name = ident.to_string();
let mut out = TokenStream::new();
out.extend(quote!(
fn deserialize(deserializer: &mut ::instant_xml::Deserializer<'xml>) -> Result<Self, ::instant_xml::Error> {
fn deserialize<'cx>(deserializer: &'cx mut ::instant_xml::Deserializer<'cx, 'xml>) -> Result<Self, ::instant_xml::Error> {
use ::instant_xml::de::{XmlRecord, Deserializer, Visitor};
use ::instant_xml::Error;
@ -137,31 +137,34 @@ impl Deserializer {
impl #xml_impl_generics Visitor<'xml> for StructVisitor #xml_ty_generics #xml_where_clause {
type Value = #ident #ty_generics;
fn visit_struct(
deserializer: &mut ::instant_xml::Deserializer<'xml>,
) -> Result<Self::Value, ::instant_xml::Error> {
use ::instant_xml::de::Node;
fn visit_struct<'cx>(
deserializer: &'cx mut ::instant_xml::Deserializer<'cx, 'xml>,
) -> Result<Self::Value, Error> {
#declare_values
while let Some(attr) = deserializer.peek_next_attribute()? {
let attr = {
#attributes_consts
match attr.id {
#attributes_names
_ => __Attributes::__Ignore
}
loop {
let node = match deserializer.next() {
Some(result) => result?,
None => break,
};
match attr {
#attr_type_match
__Attributes::__Ignore => {}
}
}
while let Some(node) = deserializer.peek_next_tag()? {
match node {
Node::Open { ns, name } => {
let id = ::instant_xml::Id { ns, name };
XmlRecord::Attribute(attr) => {
let id = deserializer.attribute_id(&attr)?;
let field = {
#attributes_consts
match id {
#attributes_names
_ => __Attributes::__Ignore
}
};
match field {
#attr_type_match
__Attributes::__Ignore => {}
}
}
XmlRecord::Open(data) => {
let id = deserializer.element_id(&data)?;
let element = {
#elements_consts
match id {
@ -173,31 +176,22 @@ impl Deserializer {
match element {
#elem_type_match
__Elements::__Ignore => {
deserializer.ignore(id)?;
let mut nested = deserializer.nested(data);
nested.ignore()?;
}
}
}
Node::Close { name } => {
if name == #name {
break;
}
},
Node::Text { text } => panic!("Unexpected element"),
_ => return Err(Error::UnexpectedState),
}
}
Ok(Self::Value {
#return_val
})
})
}
}
#namespaces_map;
deserializer.deserialize_struct::<StructVisitor>(
#name,
#default_namespace,
&namespaces_map
)
StructVisitor::visit_struct(deserializer)
}
));
@ -277,7 +271,8 @@ impl Deserializer {
panic!("duplicated value");
}
#enum_name = Some(<#no_lifetime_type>::deserialize(deserializer)?);
let mut nested = deserializer.nested(data);
#enum_name = Some(<#no_lifetime_type>::deserialize(&mut nested)?);
},
));
} else {
@ -287,8 +282,8 @@ impl Deserializer {
panic!("duplicated value");
}
deserializer.set_next_type_as_attribute()?;
#enum_name = Some(<#no_lifetime_type>::deserialize(deserializer)?);
let mut nested = deserializer.for_attr(attr);
#enum_name = Some(<#no_lifetime_type>::deserialize(&mut nested)?);
},
));
}

View File

@ -1,68 +1,134 @@
use std::collections::HashMap;
use std::iter::Peekable;
use std::collections::{BTreeMap, VecDeque};
use super::{Error, Id};
use xmlparser::{ElementEnd, Token, Tokenizer};
pub struct Deserializer<'xml> {
parser: Peekable<XmlParser<'xml>>,
def_namespaces: HashMap<&'xml str, &'xml str>,
pub parser_namespaces: HashMap<&'xml str, &'xml str>,
def_default_namespace: &'xml str,
parser_default_namespace: &'xml str,
tag_attributes: Vec<Attribute<'xml>>,
next_type: EntityType,
pub struct Deserializer<'cx, 'xml> {
pub(crate) local: &'xml str,
prefix: Option<&'xml str>,
level: usize,
done: bool,
context: &'cx mut Context<'xml>,
}
impl<'xml> Deserializer<'xml> {
pub fn new(input: &'xml str) -> Self {
impl<'cx, 'xml> Deserializer<'cx, 'xml> {
pub(crate) fn new(data: TagData<'xml>, context: &'cx mut Context<'xml>) -> Self {
let level = context.stack.len();
context.stack.push(data.level);
Self {
parser: XmlParser::new(input).peekable(),
def_namespaces: std::collections::HashMap::new(),
parser_namespaces: std::collections::HashMap::new(),
def_default_namespace: "",
parser_default_namespace: "",
tag_attributes: Vec::new(),
next_type: EntityType::Element,
local: data.key,
prefix: data.prefix,
level,
done: false,
context,
}
}
pub fn peek_next_tag(&mut self) -> Result<Option<Node<'xml>>, Error> {
let record = match self.parser.peek() {
Some(Ok(record)) => record,
Some(Err(err)) => return Err(err.clone()),
None => return Ok(None),
};
Ok(Some(match record {
XmlRecord::Open(TagData {
key, ns, prefix, ..
}) => {
let ns = match (ns, prefix) {
(_, Some(prefix)) => match self.parser_namespaces.get(prefix) {
Some(ns) => ns,
None => return Err(Error::WrongNamespace),
},
(Some(ns), None) => ns,
(None, None) => self.parser_default_namespace,
};
Node::Open { ns, name: key }
}
XmlRecord::Element(text) => Node::Text { text },
XmlRecord::Close(name) => Node::Close { name },
}))
pub fn nested<'a>(&'a mut self, data: TagData<'xml>) -> Deserializer<'a, 'xml>
where
'cx: 'a,
{
Deserializer::new(data, self.context)
}
pub fn id(&self, item: &TagData<'xml>) -> Result<Id<'xml>, Error> {
pub fn for_attr<'a>(&'a mut self, attr: Attribute<'xml>) -> Deserializer<'a, 'xml>
where
'cx: 'a,
{
self.context
.records
.push_front(XmlRecord::AttributeValue(attr.value));
Deserializer {
local: self.local,
prefix: self.prefix,
level: self.level,
done: self.done,
context: self.context,
}
}
pub fn ignore(&mut self) -> Result<(), Error> {
loop {
match self.next() {
Some(Err(e)) => return Err(e),
Some(Ok(XmlRecord::Open(data))) => {
let mut nested = self.nested(data);
nested.ignore()?;
}
Some(_) => continue,
None => return Ok(()),
}
}
}
#[inline]
pub fn element_id(&self, item: &TagData<'xml>) -> Result<Id<'xml>, Error> {
self.context.element_id(item)
}
#[inline]
pub fn attribute_id(&self, attr: &Attribute<'xml>) -> Result<Id<'xml>, Error> {
self.context.attribute_id(attr)
}
}
impl<'xml> Iterator for Deserializer<'_, 'xml> {
type Item = Result<XmlRecord<'xml>, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
let (prefix, local) = match self.context.next() {
Some(Ok(XmlRecord::Close { prefix, local })) => (prefix, local),
item => return item,
};
if self.context.stack.len() == self.level && local == self.local && prefix == self.prefix {
self.done = true;
return None;
}
Some(Err(Error::UnexpectedState))
}
}
pub(crate) struct Context<'xml> {
parser: Tokenizer<'xml>,
stack: Vec<Level<'xml>>,
records: VecDeque<XmlRecord<'xml>>,
}
impl<'xml> Context<'xml> {
pub(crate) fn new(input: &'xml str) -> Result<(Self, TagData<'xml>), Error> {
let mut new = Self {
parser: Tokenizer::from(input),
stack: Vec::new(),
records: VecDeque::new(),
};
let root = match new.next() {
Some(result) => match result? {
XmlRecord::Open(data) => data,
_ => return Err(Error::UnexpectedState),
},
None => return Err(Error::UnexpectedEndOfStream),
};
Ok((new, root))
}
pub(crate) fn element_id(&self, item: &TagData<'xml>) -> Result<Id<'xml>, Error> {
let ns = match (item.ns, item.prefix) {
(Some(_), Some(_)) => return Err(Error::WrongNamespace),
(Some(ns), None) => ns,
(None, Some(prefix)) => match self.parser_namespaces.get(prefix) {
(_, Some(prefix)) => match self.lookup(prefix) {
Some(ns) => ns,
None => return Err(Error::WrongNamespace),
},
(None, None) => "",
(Some(ns), None) => ns,
(None, None) => self.default_ns(),
};
Ok(Id {
@ -71,276 +137,95 @@ impl<'xml> Deserializer<'xml> {
})
}
pub fn peek_next_attribute(&self) -> Result<Option<AttributeNode<'xml>>, Error> {
let attr = match self.tag_attributes.last() {
Some(attr) => attr,
None => return Ok(None),
};
fn attribute_id(&self, attr: &Attribute<'xml>) -> Result<Id<'xml>, Error> {
let ns = match attr.prefix {
Some(key) => match self.parser_namespaces.get(key) {
Some(ns) => match self.lookup(ns) {
Some(ns) => ns,
None => return Err(Error::WrongNamespace),
},
None => self.parser_default_namespace,
None => self.default_ns(),
};
Ok(Some(AttributeNode {
id: Id {
ns,
name: attr.local,
},
value: attr.value,
}))
Ok(Id {
ns,
name: &attr.local,
})
}
pub fn deserialize_struct<V>(
&mut self,
name: &str,
def_default_namespace: &'xml str,
def_namespaces: &HashMap<&'xml str, &'xml str>,
) -> Result<V::Value, Error>
where
V: Visitor<'xml>,
{
// Saveing current defined default namespace
let def_default_namespace_to_revert = self.def_default_namespace;
self.def_default_namespace = def_default_namespace;
// Adding struct defined namespaces
let new_def_namespaces = def_namespaces
fn default_ns(&self) -> &'xml str {
self.stack
.iter()
.filter(|(k, v)| self.def_namespaces.insert(k, v).is_none())
.collect::<Vec<_>>();
.rev()
.find_map(|level| level.default_ns)
.unwrap_or("")
}
// Process open tag
let tag_data = match self.parser.next() {
Some(Ok(XmlRecord::Open(item))) if item.key == name => item,
_ => return Err(Error::UnexpectedValue),
};
// Set current attributes
self.tag_attributes = tag_data.attributes;
// Saveing current parser default namespace
let parser_default_namespace_to_revert = self.parser_default_namespace;
// Set parser default namespace
match tag_data.ns {
Some(namespace) => {
self.parser_default_namespace = namespace;
}
None => {
// If there is no default namespace in the tag, check if parent default namespace equals the current one
if def_default_namespace_to_revert != self.def_default_namespace {
return Err(Error::WrongNamespace);
}
}
}
// Compare parser namespace with defined one
if self.parser_default_namespace != self.def_default_namespace {
return Err(Error::WrongNamespace);
}
// Adding parser namespaces
let new_parser_namespaces = tag_data
.prefixes
fn lookup(&self, prefix: &str) -> Option<&'xml str> {
self.stack
.iter()
.filter(|(k, v)| self.parser_namespaces.insert(k, v).is_none())
.collect::<Vec<_>>();
let ret = V::visit_struct(self)?;
// Process close tag
let item = match self.parser.next() {
Some(item) => item?,
None => return Err(Error::MissingTag),
};
match item {
XmlRecord::Close(v) if v == name => {}
_ => return Err(Error::UnexpectedTag),
}
// Removing parser namespaces
let _ = new_parser_namespaces
.iter()
.map(|(k, _)| self.parser_namespaces.remove(*k));
// Removing struct defined namespaces
let _ = new_def_namespaces
.iter()
.map(|(k, _)| self.def_namespaces.remove(*k));
// Retriving old defined namespace
self.def_default_namespace = def_default_namespace_to_revert;
// Retriving old parser namespace
self.parser_default_namespace = parser_default_namespace_to_revert;
Ok(ret)
}
pub fn set_next_type_as_attribute(&mut self) -> Result<(), Error> {
if self.next_type == EntityType::Attribute {
return Err(Error::UnexpectedState);
}
self.next_type = EntityType::Attribute;
Ok(())
}
pub fn consume_next_type(&mut self) -> EntityType {
let ret = self.next_type.clone();
self.next_type = EntityType::Element;
ret
}
pub(crate) fn deserialize_element<V>(&mut self) -> Result<V::Value, Error>
where
V: Visitor<'xml>,
{
// Process open tag
match self.parser.next() {
Some(Ok(XmlRecord::Open(_))) => {}
_ => return Err(Error::UnexpectedValue),
};
match self.parser.next() {
Some(Ok(XmlRecord::Element(v))) => {
let ret = V::visit_str(v);
self.parser.next();
ret
}
_ => Err(Error::UnexpectedValue),
}
}
pub(crate) fn deserialize_attribute<V: Visitor<'xml>>(&mut self) -> Result<V::Value, Error> {
match self.tag_attributes.pop() {
Some(attr) => V::visit_str(attr.value),
None => Err(Error::UnexpectedEndOfStream),
}
}
pub fn ignore(&mut self, id: Id<'xml>) -> Result<(), Error> {
let mut levels = 0;
while let Some(result) = self.parser.next() {
match result? {
XmlRecord::Open(item) => {
if self.id(&item)? == id {
levels += 1;
}
}
XmlRecord::Close(item) => {
if item == id.name {
levels -= 1;
if levels == 0 {
return Ok(());
}
}
}
_ => {}
}
}
Ok(())
.rev()
.find_map(|level| level.prefixes.get(prefix).map(|ns| *ns))
}
}
pub struct XmlParser<'xml> {
stack: Vec<&'xml str>,
iter: Peekable<Tokenizer<'xml>>,
}
impl<'a> XmlParser<'a> {
pub fn new(input: &'a str) -> XmlParser<'a> {
XmlParser {
stack: Vec::new(),
iter: Tokenizer::from(input).peekable(),
}
}
pub fn peek_next_tag(&mut self) -> Result<Option<XmlRecord<'a>>, Error> {
let item = match self.iter.peek() {
Some(v) => v,
None => return Ok(None),
};
match item {
Ok(Token::ElementStart { prefix, local, .. }) => {
let prefix = match prefix.is_empty() {
true => None,
false => Some(prefix.as_str()),
};
Ok(Some(XmlRecord::Open(TagData {
key: local.as_str(),
attributes: Vec::new(),
ns: Some(""),
prefixes: HashMap::new(),
prefix,
})))
}
Ok(Token::ElementEnd {
end: ElementEnd::Close(..),
..
}) => {
if self.stack.is_empty() {
return Err(Error::UnexpectedEndOfStream);
}
return Ok(Some(XmlRecord::Close(self.stack.last().unwrap())));
}
Ok(_) => Err(Error::UnexpectedToken),
Err(e) => Err(Error::Parse(*e)),
}
}
}
impl<'xml> Iterator for XmlParser<'xml> {
impl<'xml> Iterator for Context<'xml> {
type Item = Result<XmlRecord<'xml>, Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let mut key: Option<&str> = None;
let mut prefix_ret: Option<&str> = None;
let mut default_namespace = None;
let mut namespaces = HashMap::new();
let mut attributes = Vec::new();
if let Some(record) = self.records.pop_front() {
return Some(Ok(record));
}
let mut current = None;
loop {
let token = match self.iter.next() {
let token = match self.parser.next() {
Some(v) => v,
None => return None,
};
match token {
Ok(Token::ElementStart { prefix, local, .. }) => {
key = Some(local.as_str());
prefix_ret = match prefix.is_empty() {
true => None,
false => Some(prefix.as_str()),
};
let prefix = prefix.as_str();
current = Some(Level {
local: local.as_str(),
prefix: (!prefix.is_empty()).then_some(prefix),
default_ns: None,
prefixes: BTreeMap::new(),
});
}
Ok(Token::ElementEnd { end, .. }) => match end {
ElementEnd::Open => {
self.stack.push(key.unwrap());
let level = match current {
Some(level) => level,
None => return Some(Err(Error::UnexpectedState)),
};
return Some(Ok(XmlRecord::Open(TagData {
key: key.unwrap(),
attributes,
ns: default_namespace,
prefixes: namespaces,
prefix: prefix_ret,
})));
let data = TagData {
key: level.local,
prefix: level.prefix,
ns: level.default_ns,
level,
};
return Some(Ok(XmlRecord::Open(data)));
}
ElementEnd::Close(_, v) => match self.stack.pop() {
Some(last) if last == v.as_str() => {
return Some(Ok(XmlRecord::Close(last)));
ElementEnd::Close(prefix, v) => {
let level = match self.stack.pop() {
Some(level) => level,
None => return Some(Err(Error::UnexpectedState)),
};
let prefix = (!prefix.is_empty()).then_some(prefix.as_str());
match v.as_str() == level.local && prefix == level.prefix {
true => {
return Some(Ok(XmlRecord::Close {
prefix,
local: level.local,
}))
}
false => return Some(Err(Error::UnexpectedState)),
}
_ => return Some(Err(Error::UnexpectedValue)),
},
}
ElementEnd::Empty => {
todo!();
}
@ -352,18 +237,24 @@ impl<'xml> Iterator for XmlParser<'xml> {
..
}) => {
if prefix.is_empty() && local.as_str() == "xmlns" {
// Default namespace
default_namespace = Some(value.as_str());
match &mut current {
Some(level) => level.default_ns = Some(value.as_str()),
None => return Some(Err(Error::UnexpectedState)),
}
} else if prefix.as_str() == "xmlns" {
// Namespaces
namespaces.insert(local.as_str(), value.as_str());
match &mut current {
Some(level) => {
level.prefixes.insert(local.as_str(), value.as_str());
}
None => return Some(Err(Error::UnexpectedState)),
}
} else {
let prefix = (!prefix.is_empty()).then_some(prefix.as_str());
attributes.push(Attribute {
self.records.push_back(XmlRecord::Attribute(Attribute {
prefix,
local: local.as_str(),
value: value.as_str(),
});
}));
}
}
Ok(Token::Text { text }) => {
@ -383,30 +274,39 @@ pub trait Visitor<'xml>: Sized {
unimplemented!();
}
fn visit_struct(_deserializer: &mut Deserializer<'xml>) -> Result<Self::Value, Error> {
fn visit_struct<'cx>(
_deserializer: &'cx mut Deserializer<'cx, 'xml>,
) -> Result<Self::Value, Error> {
unimplemented!();
}
}
#[derive(Debug)]
pub enum XmlRecord<'xml> {
Open(TagData<'xml>),
Attribute(Attribute<'xml>),
AttributeValue(&'xml str),
Close {
prefix: Option<&'xml str>,
local: &'xml str,
},
Element(&'xml str),
Close(&'xml str),
Open(TagData<'xml>),
}
#[derive(Debug)]
pub struct TagData<'xml> {
pub key: &'xml str,
pub attributes: Vec<Attribute<'xml>>,
pub ns: Option<&'xml str>,
pub prefixes: HashMap<&'xml str, &'xml str>,
pub prefix: Option<&'xml str>,
key: &'xml str,
ns: Option<&'xml str>,
prefix: Option<&'xml str>,
level: Level<'xml>,
}
pub struct AttributeNode<'xml> {
pub id: Id<'xml>,
pub value: &'xml str,
#[derive(Debug)]
struct Level<'xml> {
local: &'xml str,
prefix: Option<&'xml str>,
default_ns: Option<&'xml str>,
prefixes: BTreeMap<&'xml str, &'xml str>,
}
#[derive(Debug)]
@ -415,15 +315,3 @@ pub struct Attribute<'xml> {
pub local: &'xml str,
pub value: &'xml str,
}
pub enum Node<'xml> {
Open { ns: &'xml str, name: &'xml str },
Close { name: &'xml str },
Text { text: &'xml str },
}
#[derive(Clone, PartialEq, Eq)]
pub enum EntityType {
Element,
Attribute,
}

View File

@ -3,7 +3,7 @@ use std::fmt;
use std::marker::PhantomData;
use std::str::FromStr;
use crate::de::{EntityType, Visitor};
use crate::de::{Visitor, XmlRecord};
use crate::{Deserializer, Error, FieldAttribute, FromXml, Kind, Serializer, ToXml};
// Deserializer
@ -12,7 +12,7 @@ where
T: FromStr,
<T as FromStr>::Err: std::fmt::Display;
impl<'xml, T> Visitor<'xml> for FromStrToVisitor<T>
impl<'xml, T: 'xml> Visitor<'xml> for FromStrToVisitor<T>
where
T: FromStr,
<T as FromStr>::Err: std::fmt::Display,
@ -40,11 +40,8 @@ impl<'xml> Visitor<'xml> for BoolVisitor {
impl<'xml> FromXml<'xml> for bool {
const KIND: Kind = Kind::Scalar;
fn deserialize(deserializer: &mut Deserializer) -> Result<Self, Error> {
match deserializer.consume_next_type() {
EntityType::Element => deserializer.deserialize_element::<BoolVisitor>(),
EntityType::Attribute => deserializer.deserialize_attribute::<BoolVisitor>(),
}
fn deserialize(deserializer: &mut Deserializer<'_, 'xml>) -> Result<Self, Error> {
deserialize_scalar::<BoolVisitor>(deserializer)
}
}
@ -99,7 +96,7 @@ where
marker: PhantomData<T>,
}
impl<'xml, T> Visitor<'xml> for NumberVisitor<T>
impl<'xml, T: 'xml> Visitor<'xml> for NumberVisitor<T>
where
T: FromStr,
<T as FromStr>::Err: std::fmt::Display,
@ -115,14 +112,7 @@ macro_rules! from_xml_for_number {
($typ:ty) => {
impl<'xml> FromXml<'xml> for $typ {
fn deserialize(deserializer: &mut Deserializer) -> Result<Self, Error> {
match deserializer.consume_next_type() {
EntityType::Element => {
deserializer.deserialize_element::<NumberVisitor<$typ>>()
}
EntityType::Attribute => {
deserializer.deserialize_attribute::<NumberVisitor<$typ>>()
}
}
deserialize_scalar::<NumberVisitor<$typ>>(deserializer)
}
const KIND: Kind = Kind::Scalar;
@ -157,11 +147,7 @@ impl<'xml> FromXml<'xml> for String {
const KIND: Kind = Kind::Scalar;
fn deserialize(deserializer: &mut Deserializer) -> Result<Self, Error> {
//<&'xml str>::deserialize(deserializer);
match deserializer.consume_next_type() {
EntityType::Element => deserializer.deserialize_element::<StringVisitor>(),
EntityType::Attribute => deserializer.deserialize_attribute::<StringVisitor>(),
}
deserialize_scalar::<StringVisitor>(deserializer)
}
}
@ -182,10 +168,7 @@ impl<'xml> FromXml<'xml> for char {
const KIND: Kind = Kind::Scalar;
fn deserialize(deserializer: &mut Deserializer) -> Result<Self, Error> {
match deserializer.consume_next_type() {
EntityType::Element => deserializer.deserialize_element::<CharVisitor>(),
EntityType::Attribute => deserializer.deserialize_attribute::<CharVisitor>(),
}
deserialize_scalar::<CharVisitor>(deserializer)
}
}
@ -205,11 +188,8 @@ impl<'a> Visitor<'a> for StrVisitor {
impl<'xml> FromXml<'xml> for &'xml str {
const KIND: Kind = Kind::Scalar;
fn deserialize(deserializer: &mut Deserializer<'xml>) -> Result<Self, Error> {
match deserializer.consume_next_type() {
EntityType::Element => deserializer.deserialize_element::<StrVisitor>(),
EntityType::Attribute => deserializer.deserialize_attribute::<StrVisitor>(),
}
fn deserialize(deserializer: &mut Deserializer<'_, 'xml>) -> Result<Self, Error> {
deserialize_scalar::<StrVisitor>(deserializer)
}
}
@ -226,11 +206,8 @@ impl<'a> Visitor<'a> for CowStrVisitor {
impl<'xml> FromXml<'xml> for Cow<'xml, str> {
const KIND: Kind = Kind::Scalar;
fn deserialize(deserializer: &mut Deserializer<'xml>) -> Result<Self, Error> {
match deserializer.consume_next_type() {
EntityType::Element => deserializer.deserialize_element::<CowStrVisitor>(),
EntityType::Attribute => deserializer.deserialize_attribute::<CowStrVisitor>(),
}
fn deserialize(deserializer: &mut Deserializer<'_, 'xml>) -> Result<Self, Error> {
deserialize_scalar::<CowStrVisitor>(deserializer)
}
}
@ -240,7 +217,7 @@ where
{
const KIND: Kind = <T>::KIND;
fn deserialize(deserializer: &mut Deserializer<'xml>) -> Result<Self, Error> {
fn deserialize<'cx>(deserializer: &'cx mut Deserializer<'cx, 'xml>) -> Result<Self, Error> {
match <T>::deserialize(deserializer) {
Ok(v) => Ok(Some(v)),
Err(e) => Err(e),
@ -384,6 +361,27 @@ impl<T: ToXml> ToXml for Option<T> {
}
}
fn deserialize_scalar<'xml, V: Visitor<'xml>>(
deserializer: &mut Deserializer<'_, 'xml>,
) -> Result<V::Value, Error>
where
V::Value: FromXml<'xml>,
{
let value = match deserializer.next() {
Some(Ok(XmlRecord::AttributeValue(s))) => return V::visit_str(s),
Some(Ok(XmlRecord::Element(s))) => V::visit_str(s)?,
Some(Ok(_)) => return Err(Error::ExpectedScalar),
Some(Err(e)) => return Err(e),
None => return <V::Value as FromXml<'_>>::missing_value(),
};
match deserializer.next() {
Some(Ok(_)) => Err(Error::UnexpectedState),
Some(Err(e)) => Err(e),
None => Ok(value),
}
}
fn escape(input: &str) -> Result<Cow<'_, str>, Error> {
let mut result = String::with_capacity(input.len());
let mut last_end = 0;

View File

@ -7,6 +7,7 @@ pub use macros::{FromXml, ToXml};
#[doc(hidden)]
pub mod de;
mod impls;
use de::Context;
pub use de::Deserializer;
#[doc(hidden)]
pub mod ser;
@ -26,7 +27,7 @@ pub enum FieldAttribute<'xml> {
}
pub trait FromXml<'xml>: Sized {
fn deserialize(deserializer: &mut Deserializer<'xml>) -> Result<Self, Error>;
fn deserialize<'cx>(deserializer: &'cx mut Deserializer<'cx, 'xml>) -> Result<Self, Error>;
// If the missing field is of type `Option<T>` then treat is as `None`,
// otherwise it is an error.
@ -38,7 +39,18 @@ pub trait FromXml<'xml>: Sized {
}
pub fn from_str<'xml, T: FromXml<'xml>>(input: &'xml str) -> Result<T, Error> {
T::deserialize(&mut Deserializer::new(input))
let (mut context, root) = Context::new(input)?;
let id = context.element_id(&root)?;
let expected = match T::KIND {
Kind::Scalar => return Err(Error::UnexpectedState),
Kind::Element(expected) => expected,
};
if id != expected {
return Err(Error::UnexpectedValue);
}
T::deserialize(&mut Deserializer::new(root, &mut context))
}
pub fn to_string(value: &(impl ToXml + ?Sized)) -> Result<String, Error> {
@ -100,6 +112,8 @@ pub enum Error {
MissingdPrefix,
#[error("unexpected state")]
UnexpectedState,
#[error("expected scalar")]
ExpectedScalar,
#[error("wrong namespace")]
WrongNamespace,
}

View File

@ -39,7 +39,7 @@ fn default_namespaces() {
from_str(
"<NestedDe xmlns=\"WRONG\" xmlns:bar=\"BAZ\"><bar:flag>true</bar:flag></NestedDe>"
),
Err::<NestedDe, _>(Error::WrongNamespace)
Err::<NestedDe, _>(Error::UnexpectedValue)
);
// Correct child namespace