Separate Context out of Deserializer

This commit is contained in:
Dirkjan Ochtman 2022-09-06 12:26:23 +02:00
parent 859df7ae24
commit 11cca274b2
5 changed files with 290 additions and 395 deletions

View File

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

View File

@ -1,68 +1,134 @@
use std::collections::HashMap; use std::collections::{BTreeMap, VecDeque};
use std::iter::Peekable;
use super::{Error, Id}; use super::{Error, Id};
use xmlparser::{ElementEnd, Token, Tokenizer}; use xmlparser::{ElementEnd, Token, Tokenizer};
pub struct Deserializer<'xml> { pub struct Deserializer<'cx, 'xml> {
parser: Peekable<XmlParser<'xml>>, pub(crate) local: &'xml str,
def_namespaces: HashMap<&'xml str, &'xml str>, prefix: Option<&'xml str>,
pub parser_namespaces: HashMap<&'xml str, &'xml str>, level: usize,
def_default_namespace: &'xml str, done: bool,
parser_default_namespace: &'xml str, context: &'cx mut Context<'xml>,
tag_attributes: Vec<Attribute<'xml>>,
next_type: EntityType,
} }
impl<'xml> Deserializer<'xml> { impl<'cx, 'xml> Deserializer<'cx, 'xml> {
pub fn new(input: &'xml str) -> Self { pub(crate) fn new(data: TagData<'xml>, context: &'cx mut Context<'xml>) -> Self {
let level = context.stack.len();
context.stack.push(data.level);
Self { Self {
parser: XmlParser::new(input).peekable(), local: data.key,
def_namespaces: std::collections::HashMap::new(), prefix: data.prefix,
parser_namespaces: std::collections::HashMap::new(), level,
def_default_namespace: "", done: false,
parser_default_namespace: "", context,
tag_attributes: Vec::new(),
next_type: EntityType::Element,
} }
} }
pub fn peek_next_tag(&mut self) -> Result<Option<Node<'xml>>, Error> { pub fn nested<'a>(&'a mut self, data: TagData<'xml>) -> Deserializer<'a, 'xml>
let record = match self.parser.peek() { where
Some(Ok(record)) => record, 'cx: 'a,
Some(Err(err)) => return Err(err.clone()), {
None => return Ok(None), Deserializer::new(data, self.context)
};
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 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) { let ns = match (item.ns, item.prefix) {
(Some(_), Some(_)) => return Err(Error::WrongNamespace), (_, Some(prefix)) => match self.lookup(prefix) {
(Some(ns), None) => ns,
(None, Some(prefix)) => match self.parser_namespaces.get(prefix) {
Some(ns) => ns, Some(ns) => ns,
None => return Err(Error::WrongNamespace), None => return Err(Error::WrongNamespace),
}, },
(None, None) => "", (Some(ns), None) => ns,
(None, None) => self.default_ns(),
}; };
Ok(Id { Ok(Id {
@ -71,276 +137,95 @@ impl<'xml> Deserializer<'xml> {
}) })
} }
pub fn peek_next_attribute(&self) -> Result<Option<AttributeNode<'xml>>, Error> { fn attribute_id(&self, attr: &Attribute<'xml>) -> Result<Id<'xml>, Error> {
let attr = match self.tag_attributes.last() {
Some(attr) => attr,
None => return Ok(None),
};
let ns = match attr.prefix { let ns = match attr.prefix {
Some(key) => match self.parser_namespaces.get(key) { Some(ns) => match self.lookup(ns) {
Some(ns) => ns, Some(ns) => ns,
None => return Err(Error::WrongNamespace), None => return Err(Error::WrongNamespace),
}, },
None => self.parser_default_namespace, None => self.default_ns(),
}; };
Ok(Some(AttributeNode { Ok(Id {
id: Id { ns,
ns, name: attr.local,
name: attr.local, })
},
value: attr.value,
}))
} }
pub fn deserialize_struct<V>( fn default_ns(&self) -> &'xml str {
&mut self, self.stack
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
.iter() .iter()
.filter(|(k, v)| self.def_namespaces.insert(k, v).is_none()) .rev()
.collect::<Vec<_>>(); .find_map(|level| level.default_ns)
.unwrap_or("")
}
// Process open tag fn lookup(&self, prefix: &str) -> Option<&'xml str> {
let tag_data = match self.parser.next() { self.stack
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
.iter() .iter()
.filter(|(k, v)| self.parser_namespaces.insert(k, v).is_none()) .rev()
.collect::<Vec<_>>(); .find_map(|level| level.prefixes.get(prefix).copied())
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(())
} }
} }
pub struct XmlParser<'xml> { impl<'xml> Iterator for Context<'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> {
type Item = Result<XmlRecord<'xml>, Error>; type Item = Result<XmlRecord<'xml>, Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let mut key: Option<&str> = None; if let Some(record) = self.records.pop_front() {
let mut prefix_ret: Option<&str> = None; return Some(Ok(record));
let mut default_namespace = None; }
let mut namespaces = HashMap::new();
let mut attributes = Vec::new();
let mut current = None;
loop { loop {
let token = match self.iter.next() { let token = match self.parser.next() {
Some(v) => v, Some(v) => v,
None => return None, None => return None,
}; };
match token { match token {
Ok(Token::ElementStart { prefix, local, .. }) => { Ok(Token::ElementStart { prefix, local, .. }) => {
key = Some(local.as_str()); let prefix = prefix.as_str();
prefix_ret = match prefix.is_empty() { current = Some(Level {
true => None, local: local.as_str(),
false => Some(prefix.as_str()), prefix: (!prefix.is_empty()).then_some(prefix),
}; default_ns: None,
prefixes: BTreeMap::new(),
});
} }
Ok(Token::ElementEnd { end, .. }) => match end { Ok(Token::ElementEnd { end, .. }) => match end {
ElementEnd::Open => { 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 { let data = TagData {
key: key.unwrap(), key: level.local,
attributes, prefix: level.prefix,
ns: default_namespace, ns: level.default_ns,
prefixes: namespaces, level,
prefix: prefix_ret, };
})));
return Some(Ok(XmlRecord::Open(data)));
} }
ElementEnd::Close(_, v) => match self.stack.pop() { ElementEnd::Close(prefix, v) => {
Some(last) if last == v.as_str() => { let level = match self.stack.pop() {
return Some(Ok(XmlRecord::Close(last))); 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 => { ElementEnd::Empty => {
todo!(); todo!();
} }
@ -352,18 +237,24 @@ impl<'xml> Iterator for XmlParser<'xml> {
.. ..
}) => { }) => {
if prefix.is_empty() && local.as_str() == "xmlns" { if prefix.is_empty() && local.as_str() == "xmlns" {
// Default namespace match &mut current {
default_namespace = Some(value.as_str()); Some(level) => level.default_ns = Some(value.as_str()),
None => return Some(Err(Error::UnexpectedState)),
}
} else if prefix.as_str() == "xmlns" { } else if prefix.as_str() == "xmlns" {
// Namespaces match &mut current {
namespaces.insert(local.as_str(), value.as_str()); Some(level) => {
level.prefixes.insert(local.as_str(), value.as_str());
}
None => return Some(Err(Error::UnexpectedState)),
}
} else { } else {
let prefix = (!prefix.is_empty()).then_some(prefix.as_str()); let prefix = (!prefix.is_empty()).then_some(prefix.as_str());
attributes.push(Attribute { self.records.push_back(XmlRecord::Attribute(Attribute {
prefix, prefix,
local: local.as_str(), local: local.as_str(),
value: value.as_str(), value: value.as_str(),
}); }));
} }
} }
Ok(Token::Text { text }) => { Ok(Token::Text { text }) => {
@ -383,30 +274,39 @@ pub trait Visitor<'xml>: Sized {
unimplemented!(); 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!(); unimplemented!();
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub enum XmlRecord<'xml> { pub enum XmlRecord<'xml> {
Open(TagData<'xml>), Attribute(Attribute<'xml>),
AttributeValue(&'xml str),
Close {
prefix: Option<&'xml str>,
local: &'xml str,
},
Element(&'xml str), Element(&'xml str),
Close(&'xml str), Open(TagData<'xml>),
} }
#[derive(Debug)] #[derive(Debug)]
pub struct TagData<'xml> { pub struct TagData<'xml> {
pub key: &'xml str, key: &'xml str,
pub attributes: Vec<Attribute<'xml>>, ns: Option<&'xml str>,
pub ns: Option<&'xml str>, prefix: Option<&'xml str>,
pub prefixes: HashMap<&'xml str, &'xml str>, level: Level<'xml>,
pub prefix: Option<&'xml str>,
} }
pub struct AttributeNode<'xml> { #[derive(Debug)]
pub id: Id<'xml>, struct Level<'xml> {
pub value: &'xml str, local: &'xml str,
prefix: Option<&'xml str>,
default_ns: Option<&'xml str>,
prefixes: BTreeMap<&'xml str, &'xml str>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -415,15 +315,3 @@ pub struct Attribute<'xml> {
pub local: &'xml str, pub local: &'xml str,
pub value: &'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::marker::PhantomData;
use std::str::FromStr; use std::str::FromStr;
use crate::de::{EntityType, Visitor}; use crate::de::{Visitor, XmlRecord};
use crate::{Deserializer, Error, FieldAttribute, FromXml, Kind, Serializer, ToXml}; use crate::{Deserializer, Error, FieldAttribute, FromXml, Kind, Serializer, ToXml};
// Deserializer // Deserializer
@ -12,7 +12,7 @@ where
T: FromStr, T: FromStr,
<T as FromStr>::Err: std::fmt::Display; <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 where
T: FromStr, T: FromStr,
<T as FromStr>::Err: std::fmt::Display, <T as FromStr>::Err: std::fmt::Display,
@ -40,11 +40,8 @@ impl<'xml> Visitor<'xml> for BoolVisitor {
impl<'xml> FromXml<'xml> for bool { impl<'xml> FromXml<'xml> for bool {
const KIND: Kind = Kind::Scalar; const KIND: Kind = Kind::Scalar;
fn deserialize(deserializer: &mut Deserializer) -> Result<Self, Error> { fn deserialize(deserializer: &mut Deserializer<'_, 'xml>) -> Result<Self, Error> {
match deserializer.consume_next_type() { deserialize_scalar::<BoolVisitor>(deserializer)
EntityType::Element => deserializer.deserialize_element::<BoolVisitor>(),
EntityType::Attribute => deserializer.deserialize_attribute::<BoolVisitor>(),
}
} }
} }
@ -99,7 +96,7 @@ where
marker: PhantomData<T>, marker: PhantomData<T>,
} }
impl<'xml, T> Visitor<'xml> for NumberVisitor<T> impl<'xml, T: 'xml> Visitor<'xml> for NumberVisitor<T>
where where
T: FromStr, T: FromStr,
<T as FromStr>::Err: std::fmt::Display, <T as FromStr>::Err: std::fmt::Display,
@ -115,14 +112,7 @@ macro_rules! from_xml_for_number {
($typ:ty) => { ($typ:ty) => {
impl<'xml> FromXml<'xml> for $typ { impl<'xml> FromXml<'xml> for $typ {
fn deserialize(deserializer: &mut Deserializer) -> Result<Self, Error> { fn deserialize(deserializer: &mut Deserializer) -> Result<Self, Error> {
match deserializer.consume_next_type() { deserialize_scalar::<NumberVisitor<$typ>>(deserializer)
EntityType::Element => {
deserializer.deserialize_element::<NumberVisitor<$typ>>()
}
EntityType::Attribute => {
deserializer.deserialize_attribute::<NumberVisitor<$typ>>()
}
}
} }
const KIND: Kind = Kind::Scalar; const KIND: Kind = Kind::Scalar;
@ -157,11 +147,7 @@ impl<'xml> FromXml<'xml> for String {
const KIND: Kind = Kind::Scalar; const KIND: Kind = Kind::Scalar;
fn deserialize(deserializer: &mut Deserializer) -> Result<Self, Error> { fn deserialize(deserializer: &mut Deserializer) -> Result<Self, Error> {
//<&'xml str>::deserialize(deserializer); deserialize_scalar::<StringVisitor>(deserializer)
match deserializer.consume_next_type() {
EntityType::Element => deserializer.deserialize_element::<StringVisitor>(),
EntityType::Attribute => deserializer.deserialize_attribute::<StringVisitor>(),
}
} }
} }
@ -182,10 +168,7 @@ impl<'xml> FromXml<'xml> for char {
const KIND: Kind = Kind::Scalar; const KIND: Kind = Kind::Scalar;
fn deserialize(deserializer: &mut Deserializer) -> Result<Self, Error> { fn deserialize(deserializer: &mut Deserializer) -> Result<Self, Error> {
match deserializer.consume_next_type() { deserialize_scalar::<CharVisitor>(deserializer)
EntityType::Element => deserializer.deserialize_element::<CharVisitor>(),
EntityType::Attribute => deserializer.deserialize_attribute::<CharVisitor>(),
}
} }
} }
@ -205,11 +188,8 @@ impl<'a> Visitor<'a> for StrVisitor {
impl<'xml> FromXml<'xml> for &'xml str { impl<'xml> FromXml<'xml> for &'xml str {
const KIND: Kind = Kind::Scalar; const KIND: Kind = Kind::Scalar;
fn deserialize(deserializer: &mut Deserializer<'xml>) -> Result<Self, Error> { fn deserialize(deserializer: &mut Deserializer<'_, 'xml>) -> Result<Self, Error> {
match deserializer.consume_next_type() { deserialize_scalar::<StrVisitor>(deserializer)
EntityType::Element => deserializer.deserialize_element::<StrVisitor>(),
EntityType::Attribute => deserializer.deserialize_attribute::<StrVisitor>(),
}
} }
} }
@ -226,11 +206,8 @@ impl<'a> Visitor<'a> for CowStrVisitor {
impl<'xml> FromXml<'xml> for Cow<'xml, str> { impl<'xml> FromXml<'xml> for Cow<'xml, str> {
const KIND: Kind = Kind::Scalar; const KIND: Kind = Kind::Scalar;
fn deserialize(deserializer: &mut Deserializer<'xml>) -> Result<Self, Error> { fn deserialize(deserializer: &mut Deserializer<'_, 'xml>) -> Result<Self, Error> {
match deserializer.consume_next_type() { deserialize_scalar::<CowStrVisitor>(deserializer)
EntityType::Element => deserializer.deserialize_element::<CowStrVisitor>(),
EntityType::Attribute => deserializer.deserialize_attribute::<CowStrVisitor>(),
}
} }
} }
@ -240,7 +217,7 @@ where
{ {
const KIND: Kind = <T>::KIND; 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) { match <T>::deserialize(deserializer) {
Ok(v) => Ok(Some(v)), Ok(v) => Ok(Some(v)),
Err(e) => Err(e), 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> { fn escape(input: &str) -> Result<Cow<'_, str>, Error> {
let mut result = String::with_capacity(input.len()); let mut result = String::with_capacity(input.len());
let mut last_end = 0; let mut last_end = 0;

View File

@ -7,6 +7,7 @@ pub use macros::{FromXml, ToXml};
#[doc(hidden)] #[doc(hidden)]
pub mod de; pub mod de;
mod impls; mod impls;
use de::Context;
pub use de::Deserializer; pub use de::Deserializer;
#[doc(hidden)] #[doc(hidden)]
pub mod ser; pub mod ser;
@ -26,7 +27,7 @@ pub enum FieldAttribute<'xml> {
} }
pub trait FromXml<'xml>: Sized { 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`, // If the missing field is of type `Option<T>` then treat is as `None`,
// otherwise it is an error. // 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> { 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> { pub fn to_string(value: &(impl ToXml + ?Sized)) -> Result<String, Error> {
@ -100,6 +112,8 @@ pub enum Error {
MissingdPrefix, MissingdPrefix,
#[error("unexpected state")] #[error("unexpected state")]
UnexpectedState, UnexpectedState,
#[error("expected scalar")]
ExpectedScalar,
#[error("wrong namespace")] #[error("wrong namespace")]
WrongNamespace, WrongNamespace,
} }

View File

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