xso: make from_bytes available without std
This also deuglifies some of the parsing code by avoiding the interaction with the I/O errors emitted from rxml::Reader.
This commit is contained in:
parent
fe0050dbd8
commit
57972e9db0
1 changed files with 37 additions and 38 deletions
|
|
@ -551,56 +551,55 @@ pub fn try_from_element<T: FromXml>(
|
||||||
unreachable!("minidom::Element did not produce enough events to complete element")
|
unreachable!("minidom::Element did not produce enough events to complete element")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
/// Attempt to parse a type implementing [`FromXml`] from a byte buffer
|
||||||
fn map_nonio_error<T>(r: Result<T, io::Error>) -> Result<T, self::error::Error> {
|
/// containing XML data.
|
||||||
match r {
|
pub fn from_bytes<T: FromXml>(mut buf: &[u8]) -> Result<T, self::error::Error> {
|
||||||
Ok(v) => Ok(v),
|
use rxml::{error::EndOrError, Parse};
|
||||||
Err(e) => match e.downcast::<rxml::Error>() {
|
|
||||||
Ok(e) => Err(e.into()),
|
|
||||||
Err(_) => unreachable!("I/O error cannot be caused by &[]"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
let mut languages = rxml::xml_lang::XmlLangStack::new();
|
||||||
fn read_start_event(
|
let mut parser = rxml::Parser::new();
|
||||||
r: &mut impl Iterator<Item = io::Result<rxml::Event>>,
|
let (name, attrs) = loop {
|
||||||
) -> Result<(rxml::QName, rxml::AttrMap), self::error::Error> {
|
match parser.parse(&mut buf, true) {
|
||||||
for ev in r {
|
Ok(Some(rxml::Event::XmlDeclaration(_, rxml::XmlVersion::V1_0))) => (),
|
||||||
match map_nonio_error(ev)? {
|
Ok(Some(rxml::Event::StartElement(_, name, attrs))) => break (name, attrs),
|
||||||
rxml::Event::XmlDeclaration(_, rxml::XmlVersion::V1_0) => (),
|
Err(EndOrError::Error(e)) => return Err(self::error::Error::XmlError(e)),
|
||||||
rxml::Event::StartElement(_, name, attrs) => return Ok((name, attrs)),
|
Ok(None) | Err(EndOrError::NeedMoreData) => {
|
||||||
_ => {
|
return Err(self::error::Error::XmlError(rxml::Error::InvalidEof(Some(
|
||||||
|
rxml::error::ErrorContext::DocumentBegin,
|
||||||
|
))))
|
||||||
|
}
|
||||||
|
Ok(Some(_)) => {
|
||||||
return Err(self::error::Error::Other(
|
return Err(self::error::Error::Other(
|
||||||
"Unexpected event at start of document",
|
"Unexpected event at start of document",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
Err(self::error::Error::XmlError(rxml::Error::InvalidEof(Some(
|
languages.push_from_attrs(&attrs);
|
||||||
rxml::error::ErrorContext::DocumentBegin,
|
let mut builder = match T::from_events(name, attrs, &Context::new(languages.current())) {
|
||||||
))))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempt to parse a type implementing [`FromXml`] from a byte buffer
|
|
||||||
/// containing XML data.
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub fn from_bytes<T: FromXml>(mut buf: &[u8]) -> Result<T, self::error::Error> {
|
|
||||||
let mut reader = rxml::XmlLangTracker::wrap(rxml::Reader::new(&mut buf));
|
|
||||||
let (name, attrs) = read_start_event(&mut reader)?;
|
|
||||||
let mut builder = match T::from_events(name, attrs, &Context::new(reader.language())) {
|
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(self::error::FromEventsError::Mismatch { .. }) => {
|
Err(self::error::FromEventsError::Mismatch { .. }) => {
|
||||||
return Err(self::error::Error::TypeMismatch)
|
return Err(self::error::Error::TypeMismatch);
|
||||||
|
}
|
||||||
|
Err(self::error::FromEventsError::Invalid(e)) => {
|
||||||
|
return Err(e);
|
||||||
}
|
}
|
||||||
Err(self::error::FromEventsError::Invalid(e)) => return Err(e),
|
|
||||||
};
|
};
|
||||||
while let Some(ev) = reader.next() {
|
|
||||||
if let Some(v) = builder.feed(map_nonio_error(ev)?, &Context::new(reader.language()))? {
|
loop {
|
||||||
return Ok(v);
|
match parser.parse(&mut buf, true) {
|
||||||
|
Ok(Some(ev)) => {
|
||||||
|
languages.handle_event(&ev);
|
||||||
|
if let Some(v) = builder.feed(ev, &Context::new(languages.current()))? {
|
||||||
|
return Ok(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(EndOrError::Error(e)) => return Err(self::error::Error::XmlError(e)),
|
||||||
|
Ok(None) | Err(EndOrError::NeedMoreData) => {
|
||||||
|
return Err(self::error::Error::XmlError(rxml::Error::InvalidEof(None)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(self::error::Error::XmlError(rxml::Error::InvalidEof(None)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue