yaserde/yaserde/src/de/mod.rs
2021-07-24 12:10:41 +02:00

134 lines
3.2 KiB
Rust

//! Generic data structure deserialization framework.
//!
use crate::YaDeserialize;
use std::io::Read;
use xml::name::OwnedName;
use xml::reader::{EventReader, ParserConfig, XmlEvent};
pub fn from_str<T: YaDeserialize>(s: &str) -> Result<T, String> {
from_reader(s.as_bytes())
}
pub fn from_reader<R: Read, T: YaDeserialize>(reader: R) -> Result<T, String> {
<T as YaDeserialize>::deserialize(&mut Deserializer::new_from_reader(reader))
}
pub struct Deserializer<R: Read> {
depth: usize,
reader: EventReader<R>,
peeked: Option<XmlEvent>,
}
impl<'de, R: Read> Deserializer<R> {
pub fn new(reader: EventReader<R>) -> Self {
Deserializer {
depth: 0,
reader,
peeked: None,
}
}
pub fn new_from_reader(reader: R) -> Self {
let config = ParserConfig::new()
.trim_whitespace(true)
.whitespace_to_characters(true)
.cdata_to_characters(true)
.ignore_comments(true)
.coalesce_characters(true);
Self::new(EventReader::new_with_config(reader, config))
}
pub fn peek(&mut self) -> Result<&XmlEvent, String> {
if self.peeked.is_none() {
self.peeked = Some(self.inner_next()?);
}
if let Some(ref next) = self.peeked {
Ok(next)
} else {
Err("unable to peek next item".into())
}
}
pub fn inner_next(&mut self) -> Result<XmlEvent, String> {
loop {
match self.reader.next() {
Ok(next) => {
match next {
XmlEvent::StartDocument { .. }
| XmlEvent::ProcessingInstruction { .. }
| XmlEvent::Comment(_) => { /* skip */ }
other => return Ok(other),
}
}
Err(msg) => {
return Err(msg.msg().to_string());
}
}
}
}
pub fn next_event(&mut self) -> Result<XmlEvent, String> {
let next_event = if let Some(peeked) = self.peeked.take() {
peeked
} else {
self.inner_next()?
};
match next_event {
XmlEvent::StartElement { .. } => {
self.depth += 1;
}
XmlEvent::EndElement { .. } => {
self.depth -= 1;
}
_ => {}
}
log::debug!("Fetched {:?}, new depth {}", next_event, self.depth);
Ok(next_event)
}
pub fn skip_element(&mut self, mut cb: impl FnMut(&XmlEvent)) -> Result<(), String> {
let depth = self.depth;
while self.depth >= depth {
cb(&self.next_event()?);
}
Ok(())
}
pub fn depth(&self) -> usize {
self.depth
}
pub fn read_inner_value<T, F: FnOnce(&mut Self) -> Result<T, String>>(
&mut self,
f: F,
) -> Result<T, String> {
if let Ok(XmlEvent::StartElement { name, .. }) = self.next_event() {
let result = f(self)?;
self.expect_end_element(&name)?;
Ok(result)
} else {
Err("Internal error: Bad Event".to_string())
}
}
pub fn expect_end_element(&mut self, start_name: &OwnedName) -> Result<(), String> {
if let XmlEvent::EndElement { name, .. } = self.next_event()? {
if name == *start_name {
Ok(())
} else {
Err(format!(
"End tag </{}> didn't match the start tag <{}>",
name.local_name, start_name.local_name
))
}
} else {
Err(format!("Unexpected token </{}>", start_name.local_name))
}
}
}