use crate::element::Element;
use crate::error::{Error, ParserError, Result};
use bytes::BytesMut;
use quick_xml::Reader as EventReader;
use std::cell::RefCell;
use std::str;
#[derive(Debug)]
pub struct Parser {
buffer: RefCell<BytesMut>,
state: ParserState,
}
#[derive(Debug)]
pub enum ParserState {
Empty,
Root {
root: Element,
child: Option<Element>,
sent: bool,
},
Error,
Closed,
}
#[derive(Debug)]
pub enum ParserResult {
Partial,
Single(Element),
}
fn maybe_split_prolog(string: &str) -> &str {
if string.starts_with("<?xml") {
let mut stuff = string.splitn(2, '>');
stuff.next();
stuff.next().unwrap()
} else {
string
}
}
impl Parser {
pub fn new() -> Parser {
Parser {
buffer: RefCell::new(BytesMut::new()),
state: ParserState::Empty,
}
}
pub fn feed(&mut self, bytes: BytesMut) -> Result<()> {
self.buffer.borrow_mut().unsplit(bytes);
let state = match self.state {
ParserState::Empty => {
let foo = self.buffer.borrow();
let header = maybe_split_prolog(str::from_utf8(foo.as_ref())?);
println!("FOO: header: {:?}", header);
let mut reader = EventReader::from_str(header);
let root = Element::from_reader(&mut reader);
match root {
Ok(root) => {
println!("FOO: elem: {:?}", root);
ParserState::Root {
root,
child: None,
sent: false,
}
}
Err(e) => {
println!("FOO: err: {:?}", e);
ParserState::Empty
}
}
}
ParserState::Closed => return Err(Error::ParserError(ParserError::Closed)),
_ => ParserState::Empty,
};
self.state = state;
Ok(())
}
pub fn poll(&mut self) -> Result<Option<ParserResult>> {
match &self.state {
ParserState::Empty if self.buffer.borrow().len() != 0 => {
Ok(Some(ParserResult::Partial))
}
ParserState::Empty | ParserState::Closed | ParserState::Error => Ok(None),
ParserState::Root {
root, child: None, ..
} => Ok(Some(ParserResult::Single(root.clone()))),
ParserState::Root {
child: Some(child), ..
} => Ok(Some(ParserResult::Single(child.clone()))),
}
}
pub fn reset(&mut self) {
*self = Parser::new();
}
}
#[cfg(test)]
mod tests {
use super::*;
use bytes::{BufMut, BytesMut};
#[test]
fn test_prolog() {
let mut parser = Parser::new();
let mut buf = BytesMut::new();
buf.put(&b"<?xml version='1.0'?>"[..]);
buf.put(&b"<stream:stream xmlns='jabber:client' xml:lang='en' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' to='foo.bar'>"[..]);
match parser.feed(buf) {
Ok(_) => (),
_ => panic!(),
}
let elem = Element::builder("stream:stream", "http://etherx.jabber.org/streams")
.prefix_ns(None, "jabber:client")
.attr("xml:lang", "en")
.attr("version", "1.0")
.attr("to", "foo.bar")
.build();
println!("BAR: elem: {:?}", elem);
match parser.poll() {
Ok(Some(ParserResult::Single(e))) => assert_eq!(e, elem),
_ => panic!(),
}
}
}