use std::io::BufRead;
use std::sync::{Arc, Mutex};
use crate::document::XmlDocument;
use crate::error::Result;
use crate::event::{StreamingParser, XmlEvent, XmlEventHandler};
use super::{ParserOptions, parse_from_bufread, parse_with_options};
enum Source<'a> {
Bytes(&'a [u8]),
Reader(Box<dyn BufRead + 'a>),
}
pub struct Parser<'a> {
source: Source<'a>,
options: ParserOptions,
}
impl<'a> From<&'a str> for Parser<'a> {
fn from(xml: &'a str) -> Self {
Self::from_bytes(xml.as_bytes())
}
}
impl<'a> From<&'a [u8]> for Parser<'a> {
fn from(xml: &'a [u8]) -> Self {
Self::from_bytes(xml)
}
}
impl<'a> Parser<'a> {
fn from_bytes(bytes: &'a [u8]) -> Self {
Parser {
source: Source::Bytes(bytes),
options: ParserOptions::default(),
}
}
pub fn from_reader<R: BufRead + 'a>(reader: R) -> Self {
Parser {
source: Source::Reader(Box::new(reader)),
options: ParserOptions::default(),
}
}
pub fn options(mut self, options: ParserOptions) -> Self {
self.options = options;
self
}
pub fn parse(self) -> Result<XmlDocument> {
match self.source {
Source::Bytes(bytes) => parse_with_options(bytes, &self.options),
Source::Reader(reader) => parse_from_bufread(reader, &self.options),
}
}
pub fn events(self) -> Result<Vec<XmlEvent>> {
match self.source {
Source::Bytes(bytes) => collect_events(bytes),
Source::Reader(reader) => collect_events(reader),
}
}
pub fn for_each_event<F>(self, on_event: F) -> Result<()>
where
F: FnMut(&XmlEvent) -> Result<()>,
{
match self.source {
Source::Bytes(bytes) => {
let mut parser = StreamingParser::new(bytes);
parser.for_each_event(on_event)
}
Source::Reader(reader) => {
let mut parser = StreamingParser::new(reader);
parser.for_each_event(on_event)
}
}
}
}
fn collect_events<R: BufRead>(reader: R) -> Result<Vec<XmlEvent>> {
let collected = Arc::new(Mutex::new(Vec::new()));
let mut parser = StreamingParser::new(reader);
parser.add_handler(Box::new(CollectHandler(Arc::clone(&collected))));
parser.parse()?;
let events = std::mem::take(&mut *collected.lock().unwrap());
Ok(events)
}
struct CollectHandler(Arc<Mutex<Vec<XmlEvent>>>);
impl XmlEventHandler for CollectHandler {
fn handle(&mut self, event: &XmlEvent) -> Result<()> {
self.0.lock().unwrap().push(event.clone());
Ok(())
}
fn as_any(self: Box<Self>) -> Box<dyn std::any::Any> {
self
}
}