diff --git a/xso/src/lib.rs b/xso/src/lib.rs index 8880f79b921a512bb22533cf7d196aac78794cc7..d86c8c7d8d14f72fc0a28163235dd3c52972f6e1 100644 --- a/xso/src/lib.rs +++ b/xso/src/lib.rs @@ -551,56 +551,55 @@ pub fn try_from_element( unreachable!("minidom::Element did not produce enough events to complete element") } -#[cfg(feature = "std")] -fn map_nonio_error(r: Result) -> Result { - match r { - Ok(v) => Ok(v), - Err(e) => match e.downcast::() { - Ok(e) => Err(e.into()), - Err(_) => unreachable!("I/O error cannot be caused by &[]"), - }, - } -} +/// Attempt to parse a type implementing [`FromXml`] from a byte buffer +/// containing XML data. +pub fn from_bytes(mut buf: &[u8]) -> Result { + use rxml::{error::EndOrError, Parse}; -#[cfg(feature = "std")] -fn read_start_event( - r: &mut impl Iterator>, -) -> Result<(rxml::QName, rxml::AttrMap), self::error::Error> { - for ev in r { - match map_nonio_error(ev)? { - rxml::Event::XmlDeclaration(_, rxml::XmlVersion::V1_0) => (), - rxml::Event::StartElement(_, name, attrs) => return Ok((name, attrs)), - _ => { + let mut languages = rxml::xml_lang::XmlLangStack::new(); + let mut parser = rxml::Parser::new(); + let (name, attrs) = loop { + match parser.parse(&mut buf, true) { + Ok(Some(rxml::Event::XmlDeclaration(_, rxml::XmlVersion::V1_0))) => (), + Ok(Some(rxml::Event::StartElement(_, name, attrs))) => break (name, attrs), + 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(Some( + rxml::error::ErrorContext::DocumentBegin, + )))) + } + Ok(Some(_)) => { return Err(self::error::Error::Other( "Unexpected event at start of document", )) } } - } - Err(self::error::Error::XmlError(rxml::Error::InvalidEof(Some( - rxml::error::ErrorContext::DocumentBegin, - )))) -} - -/// Attempt to parse a type implementing [`FromXml`] from a byte buffer -/// containing XML data. -#[cfg(feature = "std")] -pub fn from_bytes(mut buf: &[u8]) -> Result { - 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())) { + }; + languages.push_from_attrs(&attrs); + let mut builder = match T::from_events(name, attrs, &Context::new(languages.current())) { Ok(v) => v, 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()))? { - return Ok(v); + + loop { + 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")]