pub use self::reader::{XmlReader};
pub use self::writer::{XmlWriter};
mod reader {
use quick_xml::Reader;
use quick_xml::events::{BytesStart, Event};
use std::io::BufRead;
use super::super::alias::{BufferType, ResultType};
use super::super::error::ErrorKind;
macro_rules! xml_seek {
($event:ident, $self:ident, $buffer:ident, $name:ident, $depth:ident)
=>
({
loop {
match $self.read_event($buffer) {
Err(e) => return Some(Err(e)),
Ok(v) => match v {
Event::$event(e) => {
if $self.found_depth($depth) && $self.found_name($name, e.name()) {
return Some(Ok(()));
}
},
Event::Eof => return None,
_ => (),
}
}
$buffer.clear();
}
})
}
struct XmlState<T: BufRead> {
reader: Reader<T>,
raw_depth: usize,
is_start: bool,
}
impl<T: BufRead> XmlState<T> {
#[inline]
pub fn new(reader: T) -> Self {
let mut reader = Reader::from_reader(reader);
reader.expand_empty_elements(true);
XmlState {
reader: reader,
raw_depth: 0,
is_start: false,
}
}
#[inline(always)]
pub fn depth(&self) -> usize {
self.raw_depth - self.is_start as usize
}
#[inline]
pub fn read_event<'a>(&mut self, buffer: &'a mut BufferType)
-> ResultType<Event<'a>>
{
match self.reader.read_event(buffer) {
Ok(Event::Start(e)) => {
self.raw_depth += 1;
self.is_start = true;
Ok(Event::Start(e))
},
Ok(Event::End(e)) => {
self.raw_depth -= 1;
self.is_start = false;
Ok(Event::End(e))
}
Ok(event) => {
self.is_start = false;
Ok(event)
},
Err(e) => {
self.is_start = false;
Err(From::from(ErrorKind::Xml(e)))
},
}
}
#[inline]
pub fn read_to_end(&mut self, buffer: &mut BufferType, name: &[u8])
-> ResultType<BufferType>
{
match self.reader.read_to_end(name, buffer) {
Err(e) => return Err(From::from(ErrorKind::Xml(e))),
Ok(_) => self.is_start = false,
}
let result = buffer.clone();
self.raw_depth -= 1;
buffer.clear();
Ok(result)
}
#[inline]
pub fn read_text(&mut self, buffer: &mut BufferType, name: &[u8])
-> ResultType<String>
{
let result = match self.reader.read_text(name, buffer) {
Err(e) => Err(From::from(ErrorKind::Xml(e))),
Ok(v) => {
self.is_start = false;
Ok(v)
},
};
self.raw_depth -= 1;
buffer.clear();
result
}
#[inline(always)]
fn found_depth(&self, depth: usize) -> bool {
return depth == usize::max_value() || self.depth() == depth;
}
#[inline(always)]
fn found_name(&self, expected: &[u8], actual: &[u8]) -> bool {
return expected == b"" || actual == expected;
}
fn seek_start_callback_impl<State, Callback>(
&mut self,
buffer: &mut BufferType,
name: &[u8],
depth: usize,
state: &mut State,
callback: Callback
)
-> Option<ResultType<bool>>
where Callback: Fn(BytesStart, &mut State) -> Option<ResultType<bool>>
{
loop {
match self.read_event(buffer) {
Err(e) => return Some(Err(e)),
Ok(v) => match v {
Event::Start(e) => {
if self.found_depth(depth) && self.found_name(name, e.name()) {
return callback(e, state);
}
},
Event::Eof => return None,
_ => (),
}
}
buffer.clear();
}
}
pub fn seek_start_callback<State, Callback>(
&mut self,
buffer: &mut BufferType,
name: &[u8],
depth: usize,
state: &mut State,
callback: Callback
)
-> Option<ResultType<bool>>
where Callback: Fn(BytesStart, &mut State) -> Option<ResultType<bool>>
{
let result = self.seek_start_callback_impl(buffer,name, depth,state, callback);
buffer.clear();
result
}
#[inline]
fn seek_start_impl(&mut self, buffer: &mut BufferType, name: &[u8], depth: usize)
-> Option<ResultType<()>>
{
xml_seek!(Start, self, buffer, name, depth)
}
#[inline]
pub fn seek_start(&mut self, buffer: &mut BufferType, name: &[u8], depth: usize)
-> Option<ResultType<()>>
{
let result = self.seek_start_impl(buffer,name, depth);
buffer.clear();
result
}
#[inline]
fn seek_end_impl(&mut self, buffer: &mut BufferType, name: &[u8], depth: usize)
-> Option<ResultType<()>>
{
xml_seek!(End, self, buffer, name, depth)
}
#[inline]
pub fn seek_end(&mut self, buffer: &mut BufferType, name: &[u8], depth: usize)
-> Option<ResultType<()>>
{
let result = self.seek_end_impl(buffer,name, depth);
buffer.clear();
result
}
fn seek_start_or_fallback_impl(
&mut self,
buffer: &mut BufferType,
name1: &[u8],
depth1: usize,
name2: &[u8],
depth2: usize,
)
-> Option<ResultType<bool>>
{
loop {
match self.read_event(buffer) {
Err(e) => return Some(Err(e)),
Ok(v) => match v {
Event::Start(e) => {
if self.found_depth(depth1) && self.found_name(name1, e.name()) {
return Some(Ok(true));
} else if self.found_depth(depth2) && self.found_name(name2, e.name()) {
return Some(Ok(false));
}
},
Event::Eof => return None,
_ => (),
}
}
buffer.clear();
}
}
#[inline]
pub fn seek_start_or_fallback(
&mut self,
buffer: &mut BufferType,
name1: &[u8],
depth1: usize,
name2: &[u8],
depth2: usize,
)
-> Option<ResultType<bool>>
{
let result = self.seek_start_or_fallback_impl(buffer, name1, depth1, name2, depth2);
buffer.clear();
result
}
}
pub struct XmlReader<T: BufRead> {
state: XmlState<T>,
buffer: BufferType,
}
impl<T: BufRead> XmlReader<T> {
#[inline]
pub fn new(reader: T) -> Self {
XmlReader {
state: XmlState::new(reader),
buffer: BufferType::with_capacity(8000),
}
}
#[inline(always)]
#[allow(dead_code)]
pub fn read_event(&mut self) -> ResultType<Event> {
self.state.read_event(&mut self.buffer)
}
#[inline(always)]
#[allow(dead_code)]
pub fn reset_buffer(&mut self) {
self.buffer.clear();
}
#[inline(always)]
#[allow(dead_code)]
pub fn read_to_end(&mut self, name: &[u8]) -> ResultType<BufferType> {
self.state.read_to_end(&mut self.buffer, name)
}
#[inline(always)]
pub fn read_text(&mut self, name: &[u8]) -> ResultType<String> {
self.state.read_text(&mut self.buffer, name)
}
#[inline(always)]
#[allow(dead_code)]
pub fn depth(&self) -> usize {
self.state.depth()
}
#[inline(always)]
#[allow(dead_code)]
pub fn buffer_position(&self) -> usize {
self.state.reader.buffer_position()
}
#[inline(always)]
pub fn seek_start_callback<State, Callback>(
&mut self,
name: &[u8],
depth: usize,
state: &mut State,
callback: Callback
)
-> Option<ResultType<bool>>
where Callback: Fn(BytesStart, &mut State) -> Option<ResultType<bool>>
{
self.state.seek_start_callback(&mut self.buffer, name, depth, state, callback)
}
#[inline(always)]
#[allow(dead_code)]
pub fn seek_start_name_callback<State, Callback>(
&mut self,
name: &[u8],
state: &mut State,
callback: Callback
)
-> Option<ResultType<bool>>
where Callback: Fn(BytesStart, &mut State) -> Option<ResultType<bool>>
{
self.seek_start_callback(name, usize::max_value(), state, callback)
}
#[inline(always)]
#[allow(dead_code)]
pub fn seek_start_depth_callback<State, Callback>(
&mut self,
depth: usize,
state: &mut State,
callback: Callback
)
-> Option<ResultType<bool>>
where Callback: Fn(BytesStart, &mut State) -> Option<ResultType<bool>>
{
self.seek_start_callback(b"", depth, state, callback)
}
#[inline(always)]
#[allow(dead_code)]
pub fn seek_start(&mut self, name: &[u8], depth: usize) -> Option<ResultType<()>> {
self.state.seek_start(&mut self.buffer, name, depth)
}
#[inline(always)]
#[allow(dead_code)]
pub fn seek_start_name(&mut self, name: &[u8]) -> Option<ResultType<()>> {
self.seek_start(name, usize::max_value())
}
#[inline(always)]
#[allow(dead_code)]
pub fn seek_start_depth(&mut self, depth: usize) -> Option<ResultType<()>> {
self.seek_start(b"", depth)
}
#[inline(always)]
pub fn seek_end(&mut self, name: &[u8], depth: usize) -> Option<ResultType<()>> {
self.state.seek_end(&mut self.buffer, name, depth)
}
#[inline]
#[allow(dead_code)]
pub fn seek_end_name(&mut self, name: &[u8]) -> Option<ResultType<()>> {
self.seek_end(name, usize::max_value())
}
#[inline]
#[allow(dead_code)]
pub fn seek_end_depth(&mut self, depth: usize) -> Option<ResultType<()>> {
self.seek_end(b"", depth)
}
#[inline]
pub fn seek_start_or_fallback(
&mut self,
name1: &[u8],
depth1: usize,
name2: &[u8],
depth2: usize,
)
-> Option<ResultType<bool>>
{
self.state.seek_start_or_fallback(&mut self.buffer, name1, depth1, name2, depth2)
}
}
}
mod writer {
use quick_xml::Writer;
use quick_xml::events::{BytesDecl, BytesEnd, BytesStart, BytesText, Event};
use std::io::Write;
use super::super::alias::ResultType;
use super::super::error::ErrorKind;
pub struct XmlWriter<T: Write> {
writer: Writer<T>,
}
impl<T: Write> XmlWriter<T> {
#[inline]
pub fn new(writer: T) -> Self {
XmlWriter {
writer: Writer::new(writer)
}
}
#[inline(always)]
#[allow(dead_code)]
pub fn into_inner(self) -> T {
self.writer.into_inner()
}
#[inline(always)]
fn new_start_element(bytes: &[u8]) -> BytesStart {
BytesStart::borrowed(bytes, bytes.len())
}
#[inline(always)]
fn new_text_element<'a>(text: &[u8]) -> BytesText {
BytesText::from_plain(text)
}
#[inline(always)]
fn new_end_element(bytes: &[u8]) -> BytesEnd {
BytesEnd::borrowed(bytes)
}
#[inline(always)]
fn write_event(&mut self, event: Event) -> ResultType<()> {
match self.writer.write_event(event) {
Err(e) => Err(From::from(ErrorKind::Xml(e))),
_ => Ok(()),
}
}
#[inline(always)]
pub fn write_declaration(&mut self) -> ResultType<()> {
let decl = BytesDecl::new(b"1.0", Some(b"UTF-8"), None);
self.write_event(Event::Decl(decl))
}
#[inline(always)]
pub fn write_start_element(&mut self, name: &[u8], attributes: &[(&[u8], &[u8])])
-> ResultType<()>
{
let mut elem = Self::new_start_element(name);
for attribute in attributes {
elem.push_attribute(*attribute);
}
self.write_event(Event::Start(elem))
}
pub fn write_text_element(&mut self, name: &[u8], text: &[u8], attributes: &[(&[u8], &[u8])])
-> ResultType<()>
{
self.write_start_element(name, attributes)?;
self.write_event(Event::Text(Self::new_text_element(text)))?;
self.write_end_element(name)
}
#[inline(always)]
pub fn write_empty_element(&mut self, name: &[u8], attributes: &[(&[u8], &[u8])])
-> ResultType<()>
{
let mut elem = Self::new_start_element(name);
for attribute in attributes {
elem.push_attribute(*attribute);
}
self.write_event(Event::Empty(elem))
}
#[inline(always)]
pub fn write_end_element(&mut self, name: &[u8])
-> ResultType<()>
{
self.write_event(Event::End(Self::new_end_element(name)))
}
}
}
#[cfg(test)]
mod tests {
use quick_xml::events::Event;
use std::io::Cursor;
use super::*;
#[test]
fn xml_declaration_test() {
let mut w = XmlWriter::new(Cursor::new(vec![]));
w.write_declaration().unwrap();
let text = String::from_utf8(w.into_inner().into_inner()).unwrap();
assert_eq!(text, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
}
#[test]
fn xml_write_test() {
let mut w = XmlWriter::new(Cursor::new(vec![]));
w.write_declaration().unwrap();
w.write_start_element(b"t1", &[(b"k1", b"v1")]).unwrap();
w.write_text_element(b"t2", b"Text", &[(b"k2", b"v2")]).unwrap();
w.write_empty_element(b"t3", &[(b"k3", b"v3")]).unwrap();
w.write_end_element(b"t1").unwrap();
let text = String::from_utf8(w.into_inner().into_inner()).unwrap();
assert_eq!(text, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><t1 k1=\"v1\"><t2 k2=\"v2\">Text</t2><t3 k3=\"v3\"/></t1>");
}
#[test]
fn xml_read_test() {
let text = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><t1 k1=\"v1\"><t2 k2=\"v2\">Text</t2><t3 k3=\"v3\"></t3></t1>";
let mut r = XmlReader::new(Cursor::new(text));
let mut tags: Vec<String> = vec![];
loop {
match r.read_event() {
Err(_) => break,
Ok(Event::Eof) => break,
Ok(Event::Start(e)) => {
let string = String::from_utf8(e.name().to_vec()).unwrap();
tags.push(string);
},
_ => continue,
}
r.reset_buffer();
}
assert_eq!(tags, &["t1", "t2", "t3"]);
}
}