use super::event::{BorrowedEvent, Event};
use super::machine::Core;
use crate::Limits;
use crate::error::Result;
#[cfg(feature = "std")]
use crate::error::{Error, ErrorKind};
use crate::external::ExternalSource;
#[cfg(feature = "std")]
use std::io;
#[cfg(feature = "std")]
const CHUNK: usize = 8192;
mod sealed {
pub trait Sealed {}
}
pub trait Source: sealed::Sealed {
#[doc(hidden)]
fn fill(&mut self, core: &mut Core<'_>) -> Result<()>;
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Complete;
impl sealed::Sealed for Complete {}
impl Source for Complete {
fn fill(&mut self, core: &mut Core<'_>) -> Result<()> {
core.feed_eof()
}
}
#[cfg(feature = "std")]
impl<R: io::BufRead> sealed::Sealed for R {}
#[cfg(feature = "std")]
impl<R: io::BufRead> Source for R {
fn fill(&mut self, core: &mut Core<'_>) -> Result<()> {
loop {
let outcome = match self.fill_buf() {
Ok([]) => core.feed_eof(),
Ok(buf) => {
let take = buf.len().min(CHUNK);
let fed = core.feed(&buf[..take]);
self.consume(take);
fed
}
Err(e) if e.kind() == io::ErrorKind::Interrupted => {
continue;
}
Err(e) => {
core.fail();
Err(Error::new(
ErrorKind::Io(e.to_string()),
core.end_offset(),
))
}
};
return outcome;
}
}
}
pub struct Reader<'e, S = Complete> {
core: Core<'e>,
source: S,
}
impl<S> core::fmt::Debug for Reader<'_, S> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Reader")
.field("core", &self.core)
.finish_non_exhaustive()
}
}
impl Reader<'_, Complete> {
pub fn new(input: &str) -> Result<Self> {
Self::with_limits(input, Limits::default())
}
pub fn with_limits(input: &str, limits: Limits) -> Result<Self> {
let (text, version) = crate::parser::prepare(input, limits)?;
let standalone = crate::parser::declared_standalone(&text);
let mut core = Core::with_limits(limits);
core.adopt(text, version, standalone)?;
Ok(Self {
core,
source: Complete,
})
}
}
#[cfg(feature = "std")]
impl<R: io::BufRead> Reader<'_, R> {
pub fn from_reader(reader: R) -> Result<Self> {
Self::from_reader_with(reader, Limits::default())
}
pub fn from_reader_with(reader: R, limits: Limits) -> Result<Self> {
let mut reader = Self {
core: Core::with_limits(limits),
source: reader,
};
while !reader.core.settled() && reader.core.needs_input() {
reader.source.fill(&mut reader.core)?;
}
Ok(reader)
}
}
impl<'e, S: Source> Reader<'e, S> {
#[must_use]
pub fn with_external(
mut self,
external: &'e (dyn ExternalSource + Sync),
) -> Self {
self.core = self.core.with_external(external);
self
}
pub fn next_event(&mut self) -> Result<Option<Event>> {
#[cfg(feature = "tracing")]
let _span = tracing::trace_span!("oxml.stream.next_event").entered();
self.next_borrowed()
.map(|opt| opt.map(BorrowedEvent::into_owned))
}
pub fn next_borrowed(&mut self) -> Result<Option<BorrowedEvent<'_>>> {
#[cfg(feature = "tracing")]
let _span = tracing::trace_span!("oxml.stream.next_borrowed").entered();
loop {
while self.core.needs_input() {
self.source.fill(&mut self.core)?;
}
self.core.prepare()?;
if !self.core.needs_input() {
break;
}
}
self.core.next_event()
}
#[must_use]
pub fn offset(&self) -> usize {
self.core.offset()
}
}
impl<S: Source> Iterator for Reader<'_, S> {
type Item = Result<Event>;
fn next(&mut self) -> Option<Self::Item> {
self.next_event().transpose()
}
}