use std::io::{BufReader, Read};
use docspec_core::{Error, Result};
use quick_xml::events::{BytesStart, Event as XmlEvent};
const SCRATCH_CAPACITY: usize = 4096;
pub(crate) struct XmlCursor {
reader: quick_xml::Reader<BufReader<Box<dyn Read + Send>>>,
scratch: Vec<u8>,
}
impl XmlCursor {
pub(crate) fn new(mut reader: quick_xml::Reader<BufReader<Box<dyn Read + Send>>>) -> Self {
reader.config_mut().check_end_names = false;
Self {
reader,
scratch: Vec::with_capacity(SCRATCH_CAPACITY),
}
}
pub(crate) fn read_owned(&mut self) -> Result<XmlEvent<'static>> {
self.scratch.clear();
Ok(self
.reader
.read_event_into(&mut self.scratch)
.map_err(map_quick_xml_error)?
.into_owned())
}
pub(crate) fn skip_subtree(&mut self, start: &BytesStart<'_>) -> Result<()> {
let end = start.to_end().into_owned();
self.reader
.read_to_end_into(end.name(), &mut self.scratch)
.map_err(map_quick_xml_error)?;
Ok(())
}
}
impl core::fmt::Debug for XmlCursor {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("XmlCursor").finish_non_exhaustive()
}
}
fn map_quick_xml_error(err: quick_xml::Error) -> Error {
match err {
quick_xml::Error::Io(source) => Error::Io {
source: std::io::Error::new(source.kind(), source.to_string()),
},
other => Error::Parse {
message: format!("malformed document.xml: {other}"),
position: None,
},
}
}