Skip to content

Commit

Permalink
Update implementation macros to support async code
Browse files Browse the repository at this point in the history
  • Loading branch information
999eagle authored and Mingun committed Aug 9, 2022
1 parent f062bbe commit b980725
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 39 deletions.
46 changes: 23 additions & 23 deletions src/reader/buffered_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use crate::name::QName;
use crate::reader::{is_whitespace, BangType, ReadElementState, Reader, XmlSource};

macro_rules! impl_buffered_source {
() => {
($($lf:lifetime, $reader:tt, $async:ident, $await:ident)?) => {
#[inline]
fn read_bytes_until(
$($async)? fn read_bytes_until $(<$lf>)? (
&mut self,
byte: u8,
buf: &'b mut Vec<u8>,
Expand All @@ -29,7 +29,7 @@ macro_rules! impl_buffered_source {
let start = buf.len();
while !done {
let used = {
let available = match self.fill_buf() {
let available = match self $(.$reader)? .fill_buf() $(.$await)? {
Ok(n) if n.is_empty() => break,
Ok(n) => n,
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
Expand All @@ -51,7 +51,7 @@ macro_rules! impl_buffered_source {
}
}
};
self.consume(used);
self $(.$reader)? .consume(used);
read += used;
}
*position += read;
Expand All @@ -63,7 +63,7 @@ macro_rules! impl_buffered_source {
}
}

fn read_bang_element(
$($async)? fn read_bang_element $(<$lf>)? (
&mut self,
buf: &'b mut Vec<u8>,
position: &mut usize,
Expand All @@ -73,20 +73,20 @@ macro_rules! impl_buffered_source {
let start = buf.len();
let mut read = 1;
buf.push(b'!');
self.consume(1);
self $(.$reader)? .consume(1);

let bang_type = BangType::new(self.peek_one()?)?;
let bang_type = BangType::new(self.peek_one() $(.$await)? ?)?;

loop {
match self.fill_buf() {
match self $(.$reader)? .fill_buf() $(.$await)? {
// Note: Do not update position, so the error points to
// somewhere sane rather than at the EOF
Ok(n) if n.is_empty() => return Err(bang_type.to_err()),
Ok(available) => {
if let Some((consumed, used)) = bang_type.parse(available, read) {
buf.extend_from_slice(consumed);

self.consume(used);
self $(.$reader)? .consume(used);
read += used;

*position += read;
Expand All @@ -95,7 +95,7 @@ macro_rules! impl_buffered_source {
buf.extend_from_slice(available);

let used = available.len();
self.consume(used);
self $(.$reader)? .consume(used);
read += used;
}
}
Expand All @@ -115,7 +115,7 @@ macro_rules! impl_buffered_source {
}

#[inline]
fn read_element(
$($async)? fn read_element $(<$lf>)? (
&mut self,
buf: &'b mut Vec<u8>,
position: &mut usize,
Expand All @@ -125,13 +125,13 @@ macro_rules! impl_buffered_source {

let start = buf.len();
loop {
match self.fill_buf() {
match self $(.$reader)? .fill_buf() $(.$await)? {
Ok(n) if n.is_empty() => break,
Ok(available) => {
if let Some((consumed, used)) = state.change(available) {
buf.extend_from_slice(consumed);

self.consume(used);
self $(.$reader)? .consume(used);
read += used;

*position += read;
Expand All @@ -140,7 +140,7 @@ macro_rules! impl_buffered_source {
buf.extend_from_slice(available);

let used = available.len();
self.consume(used);
self $(.$reader)? .consume(used);
read += used;
}
}
Expand All @@ -161,13 +161,13 @@ macro_rules! impl_buffered_source {

/// Consume and discard all the whitespace until the next non-whitespace
/// character or EOF.
fn skip_whitespace(&mut self, position: &mut usize) -> Result<()> {
$($async)? fn skip_whitespace(&mut self, position: &mut usize) -> Result<()> {
loop {
break match self.fill_buf() {
break match self $(.$reader)? .fill_buf() $(.$await)? {
Ok(n) => {
let count = n.iter().position(|b| !is_whitespace(*b)).unwrap_or(n.len());
if count > 0 {
self.consume(count);
self $(.$reader)? .consume(count);
*position += count;
continue;
} else {
Expand All @@ -182,14 +182,14 @@ macro_rules! impl_buffered_source {

/// Consume and discard one character if it matches the given byte. Return
/// true if it matched.
fn skip_one(&mut self, byte: u8, position: &mut usize) -> Result<bool> {
$($async)? fn skip_one(&mut self, byte: u8, position: &mut usize) -> Result<bool> {
// search byte must be within the ascii range
debug_assert!(byte.is_ascii());

match self.peek_one()? {
match self.peek_one() $(.$await)? ? {
Some(b) if b == byte => {
*position += 1;
self.consume(1);
self $(.$reader)? .consume(1);
Ok(true)
}
_ => Ok(false),
Expand All @@ -198,9 +198,9 @@ macro_rules! impl_buffered_source {

/// Return one character without consuming it, so that future `read_*` calls
/// will still include it. On EOF, return None.
fn peek_one(&mut self) -> Result<Option<u8>> {
$($async)? fn peek_one(&mut self) -> Result<Option<u8>> {
loop {
break match self.fill_buf() {
break match self $(.$reader)? .fill_buf() $(.$await)? {
Ok(n) if n.is_empty() => Ok(None),
Ok(n) => Ok(Some(n[0])),
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
Expand Down Expand Up @@ -353,7 +353,7 @@ impl<R: BufRead> Reader<R> {
/// [`check_end_names`]: Self::check_end_names
/// [the specification]: https://www.w3.org/TR/xml11/#dt-etag
pub fn read_to_end_into(&mut self, end: QName, buf: &mut Vec<u8>) -> Result<()> {
read_to_end!(self, end, buf, {
read_to_end!(self, end, buf, read_event_impl, {
buf.clear();
})
}
Expand Down
44 changes: 29 additions & 15 deletions src/reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,15 @@ macro_rules! configure_methods {

macro_rules! read_event_impl {
(
$self:ident, $buf:ident
$self:ident, $buf:ident,
$read_until_open:ident,
$read_until_close:ident
$(, $await:ident)?
) => {{
let event = match $self.parser.state {
ParseState::Init => $self.read_until_open($buf, true),
ParseState::ClosedTag => $self.read_until_open($buf, false),
ParseState::OpenedTag => $self.read_until_close($buf),
ParseState::Init => $self.$read_until_open($buf, true) $(.$await)?,
ParseState::ClosedTag => $self.$read_until_open($buf, false) $(.$await)?,
ParseState::OpenedTag => $self.$read_until_close($buf) $(.$await)?,
ParseState::Empty => $self.parser.close_expanded_empty(),
ParseState::Exit => return Ok(Event::Eof),
};
Expand All @@ -148,22 +151,25 @@ macro_rules! read_event_impl {

macro_rules! read_until_open {
(
$self:ident, $buf:ident, $first:ident
$self:ident, $buf:ident, $first:ident,
$read_event:ident
$(, $await:ident)?
) => {{
$self.parser.state = ParseState::OpenedTag;

if $self.parser.trim_text_start {
$self.reader.skip_whitespace(&mut $self.parser.offset)?;
$self.reader.skip_whitespace(&mut $self.parser.offset) $(.$await)? ?;
}

// If we already at the `<` symbol, do not try to return an empty Text event
if $self.reader.skip_one(b'<', &mut $self.parser.offset)? {
return $self.read_event_impl($buf);
if $self.reader.skip_one(b'<', &mut $self.parser.offset) $(.$await)? ? {
return $self.$read_event($buf) $(.$await)?;
}

match $self
.reader
.read_bytes_until(b'<', $buf, &mut $self.parser.offset)
$(.$await)?
{
Ok(Some(bytes)) => $self.parser.read_text(bytes, $first),
Ok(None) => Ok(Event::Eof),
Expand All @@ -175,41 +181,47 @@ macro_rules! read_until_open {
macro_rules! read_until_close {
(
$self:ident, $buf:ident
$(, $await:ident)?
) => {{
$self.parser.state = ParseState::ClosedTag;

match $self.reader.peek_one() {
match $self.reader.peek_one() $(.$await)? {
// `<!` - comment, CDATA or DOCTYPE declaration
Ok(Some(b'!')) => match $self
.reader
.read_bang_element($buf, &mut $self.parser.offset)
$(.$await)?
{
Ok(None) => Ok(Event::Eof),
Ok(Some((bang_type, bytes))) => $self.parser.read_bang(bang_type, bytes),
Err(e) => Err(e),
},
// `</` - closing tag
Ok(Some(b'/')) => match $self
// Comment for prevent formatting
.reader
.read_bytes_until(b'>', $buf, &mut $self.parser.offset)
$(.$await)?
{
Ok(None) => Ok(Event::Eof),
Ok(Some(bytes)) => $self.parser.read_end(bytes),
Err(e) => Err(e),
},
// `<?` - processing instruction
Ok(Some(b'?')) => match $self
// Comment for prevent formatting
.reader
.read_bytes_until(b'>', $buf, &mut $self.parser.offset)
$(.$await)?
{
Ok(None) => Ok(Event::Eof),
Ok(Some(bytes)) => $self.parser.read_question_mark(bytes),
Err(e) => Err(e),
},
// `<...` - opening or self-closed tag
Ok(Some(_)) => match $self.reader.read_element($buf, &mut $self.parser.offset) {
Ok(Some(_)) => match $self
.reader
.read_element($buf, &mut $self.parser.offset)
$(.$await)?
{
Ok(None) => Ok(Event::Eof),
Ok(Some(bytes)) => $self.parser.read_start(bytes),
Err(e) => Err(e),
Expand All @@ -224,13 +236,15 @@ macro_rules! read_until_close {
macro_rules! read_to_end {
(
$self:expr, $end:expr, $buf:expr,
$read_event:ident,
// Code block that performs clearing of internal buffer after read of each event
$clear:block
$(, $await:ident)?
) => {{
let mut depth = 0;
loop {
$clear
match $self.read_event_impl($buf) {
match $self.$read_event($buf) $(.$await)? {
Err(e) => return Err(e),

Ok(Event::Start(e)) if e.name() == $end => depth += 1,
Expand Down Expand Up @@ -528,7 +542,7 @@ impl<R> Reader<R> {
where
R: XmlSource<'i, B>,
{
read_event_impl!(self, buf)
read_event_impl!(self, buf, read_until_open, read_until_close)
}

/// Read until '<' is found and moves reader to an `OpenedTag` state.
Expand All @@ -538,7 +552,7 @@ impl<R> Reader<R> {
where
R: XmlSource<'i, B>,
{
read_until_open!(self, buf, first)
read_until_open!(self, buf, first, read_event_impl)
}

/// Private function to read until `>` is found. This function expects that
Expand Down
2 changes: 1 addition & 1 deletion src/reader/slice_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ impl<'a> Reader<&'a [u8]> {
/// [`check_end_names`]: Self::check_end_names
/// [the specification]: https://www.w3.org/TR/xml11/#dt-etag
pub fn read_to_end(&mut self, end: QName) -> Result<()> {
read_to_end!(self, end, (), {})
read_to_end!(self, end, (), read_event_impl, {})
}
}

Expand Down

0 comments on commit b980725

Please sign in to comment.