use encoding_rs::Encoding;
use quick_xml::events::attributes::{Attribute, Attributes};
use quick_xml::events::{BytesStart, Event};
use quick_xml::{Error, Reader};
use std::borrow::Cow;
use std::cell::RefCell;
use std::io::BufRead;
type BufferHandle = usize;
struct BufferManager {
buffers: Vec<Vec<u8>>,
free_buffers: Vec<BufferHandle>,
}
impl BufferManager {
fn alloc(&mut self) -> (&mut Vec<u8>, BufferHandle) {
if let Some(index) = self.free_buffers.pop() {
let mut_buffer = self.buffers.get_mut(index).unwrap();
mut_buffer.clear();
(mut_buffer, index)
} else {
let index = self.buffers.len();
self.buffers.push(Vec::new());
let mut_buffer = self.buffers.last_mut().unwrap();
(mut_buffer, index)
}
}
fn release(&mut self, index: BufferHandle) {
self.free_buffers.push(index);
}
}
pub struct PullReader<B: BufRead> {
reader: Reader<B>,
buffer_manager: RefCell<BufferManager>,
}
pub struct Element<'a, B: BufRead> {
pending_close: bool,
handle: BufferHandle,
reader: &'a mut Reader<B>,
buffer_manager: &'a RefCell<BufferManager>,
data: BytesStart<'a>,
}
pub struct AttributesView<'a> {
encoding: &'static Encoding,
attributes: Attributes<'a>,
}
pub struct AttributeView<'a> {
encoding: &'static Encoding,
attribute: Attribute<'a>,
}
pub struct Text<'a> {
encoding: &'static Encoding,
handle: Option<BufferHandle>,
buffer_manager: Option<&'a RefCell<BufferManager>>,
data: Cow<'a, [u8]>,
}
impl<B: BufRead> PullReader<B> {
pub fn new(input: B) -> Self {
let mut reader = Reader::from_reader(input);
let _ = reader
.trim_text(true)
.expand_empty_elements(true)
.check_end_names(true);
PullReader::from_reader(reader)
}
pub fn from_reader(reader: Reader<B>) -> Self {
PullReader {
reader,
buffer_manager: RefCell::new(BufferManager {
buffers: Vec::new(),
free_buffers: Vec::new(),
}),
}
}
pub fn root<'a>(&'a mut self) -> quick_xml::Result<Element<'a, B>> {
let mut buffer_manager = self.buffer_manager.borrow_mut();
let (buffer, handle) = buffer_manager.alloc();
loop {
match self.reader.read_event(buffer)? {
Event::Start(data) => {
return Ok(Element {
pending_close: false,
handle,
reader: &mut self.reader,
buffer_manager: &self.buffer_manager,
data: unsafe {
std::mem::transmute::<BytesStart<'_>, BytesStart<'a>>(data)
},
});
}
Event::Eof => {
buffer_manager.release(handle);
return Err(Error::UnexpectedEof("root".to_owned()));
}
_ => {}
}
}
}
}
impl<B: BufRead> Element<'_, B> {
pub fn name(&'_ self) -> Cow<'_, str> {
self.reader.decode(self.data.name())
}
pub fn attributes(&'_ self) -> AttributesView<'_> {
AttributesView {
encoding: self.reader.encoding(),
attributes: self.data.attributes(),
}
}
pub fn find_attribute(
&'_ self,
name: impl AsRef<str>,
) -> quick_xml::Result<Option<AttributeView<'_>>> {
for attribute in self.attributes() {
match attribute {
Ok(attribute) => {
if attribute.key().as_ref() == name.as_ref() {
return Ok(Some(attribute));
}
}
Err(error) => return Err(error),
}
}
Ok(None)
}
pub fn next_child<'a>(&'a mut self) -> quick_xml::Result<Option<Element<'a, B>>> {
if self.pending_close {
return Ok(None);
}
let mut buffer_manager = self.buffer_manager.borrow_mut();
let (buffer, handle) = buffer_manager.alloc();
loop {
buffer.clear();
match self.reader.read_event(buffer)? {
Event::Start(data) => {
return Ok(Some(Element {
pending_close: false,
handle,
buffer_manager: self.buffer_manager,
reader: self.reader,
data: unsafe {
std::mem::transmute::<BytesStart<'_>, BytesStart<'a>>(data)
},
}));
}
Event::End(_) => {
buffer_manager.release(handle);
self.pending_close = true;
return Ok(None);
}
Event::Eof => {
buffer_manager.release(handle);
return Err(Error::UnexpectedEof("next_child".to_owned()));
}
_ => {}
}
}
}
pub fn find_next_child<'a>(
&'a mut self,
name: impl AsRef<str>,
) -> quick_xml::Result<Option<Element<'a, B>>> {
let needle = self.reader.encoding().encode(name.as_ref()).0;
while let Some(element) = self.next_child()? {
if element.data.name() == needle.as_ref() {
return Ok(Some(unsafe {
std::mem::transmute::<Element<'_, B>, Element<'a, B>>(element)
}));
}
}
Ok(None)
}
pub fn try_text<'a>(&'a mut self) -> quick_xml::Result<Option<Text<'a>>> {
if self.pending_close {
return Ok(None);
}
let mut buffer_manager = self.buffer_manager.borrow_mut();
let (buffer, handle) = buffer_manager.alloc();
let mut depth = 1;
loop {
match self.reader.read_event(buffer)? {
Event::Start(_) => depth += 1,
Event::End(_) => {
depth -= 1;
if depth == 0 {
self.pending_close = true;
return Ok(None);
}
}
Event::Eof => return Err(Error::UnexpectedEof("try_text".to_owned())),
Event::Text(data) | Event::CData(data) => {
return Ok(Some(Text {
encoding: self.reader.encoding(),
handle: Some(handle),
buffer_manager: Some(self.buffer_manager),
data: unsafe {
std::mem::transmute::<Cow<'_, [u8]>, Cow<'a, [u8]>>(data.unescaped()?)
},
}));
}
_ => {}
}
}
}
pub fn text(&'_ mut self) -> quick_xml::Result<Text<'_>> {
let encoding = self.reader.encoding();
match self.try_text() {
Ok(Some(text)) => Ok(text),
Ok(None) => Ok(Text {
handle: None,
encoding,
buffer_manager: None,
data: Cow::Owned(Vec::new()),
}),
Err(error) => Err(error),
}
}
}
impl<B: BufRead> Drop for Element<'_, B> {
fn drop(&mut self) {
let mut buffer_manager = self.buffer_manager.borrow_mut();
buffer_manager.release(self.handle);
if !self.pending_close {
let mut depth = 1;
let (tmp_buffer, tmp_handle) = buffer_manager.alloc();
loop {
if let Ok(event) = self.reader.read_event(tmp_buffer) {
match event {
Event::Start(_) => depth += 1,
Event::End(_) => {
depth -= 1;
if depth == 0 {
buffer_manager.release(tmp_handle);
return;
}
}
Event::Eof => {
buffer_manager.release(tmp_handle);
return;
}
Event::Text(_) => {}
Event::CData(_) => {}
_ => {}
}
tmp_buffer.clear();
} else {
buffer_manager.release(tmp_handle);
return;
}
}
}
}
}
impl AttributeView<'_> {
pub fn key(&'_ self) -> Cow<'_, str> {
self.encoding.decode(self.attribute.key).0
}
pub fn value(&'_ self) -> quick_xml::Result<Text<'_>> {
Ok(Text {
handle: None,
buffer_manager: None,
encoding: self.encoding,
data: self.attribute.unescaped_value()?,
})
}
}
impl<'a> Iterator for AttributesView<'a> {
type Item = quick_xml::Result<AttributeView<'a>>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(attribute_result) = self.attributes.next() {
match attribute_result {
Ok(attribute) => Some(Ok(AttributeView {
encoding: self.encoding,
attribute,
})),
Err(error) => Some(Err(error)),
}
} else {
None
}
}
}
impl Text<'_> {
pub fn contents(&'_ self) -> Cow<'_, str> {
self.encoding.decode(self.data.as_ref()).0
}
}
impl Drop for Text<'_> {
fn drop(&mut self) {
if let Some(handle) = self.handle {
self.buffer_manager.unwrap().borrow_mut().release(handle);
}
}
}