use crate::errors::SyntaxError;
use crate::parser::Parser;
use crate::utils::is_whitespace;
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct PiParser(
pub bool,
);
impl Parser for PiParser {
#[inline]
fn feed(&mut self, bytes: &[u8]) -> Option<usize> {
for i in memchr::memchr_iter(b'>', bytes) {
match i {
0 if self.0 => return Some(0),
i if i > 0 && bytes[i - 1] == b'?' => return Some(i),
_ => {}
}
}
self.0 = bytes.last().copied() == Some(b'?');
None
}
#[inline]
fn eof_error(self, content: &[u8]) -> SyntaxError {
let is_xml_decl = content.starts_with(b"<?xml")
&& content
.get(5)
.map_or(true, |&b| is_whitespace(b) || b == b'?');
if is_xml_decl {
SyntaxError::UnclosedXmlDecl
} else {
SyntaxError::UnclosedPI
}
}
}
#[test]
fn pi() {
use pretty_assertions::assert_eq;
fn parse_pi(bytes: &[u8], had_question_mark: bool) -> Result<usize, bool> {
let mut parser = PiParser(had_question_mark);
match parser.feed(bytes) {
Some(i) => Ok(i),
None => Err(parser.0),
}
}
assert_eq!(parse_pi(b"", false), Err(false)); assert_eq!(parse_pi(b"", true), Err(false));
assert_eq!(parse_pi(b"?", false), Err(true)); assert_eq!(parse_pi(b"?", true), Err(true));
assert_eq!(parse_pi(b">", false), Err(false)); assert_eq!(parse_pi(b">", true), Ok(0));
assert_eq!(parse_pi(b"?>", false), Ok(1)); assert_eq!(parse_pi(b"?>", true), Ok(1));
assert_eq!(parse_pi(b">?>", false), Ok(2)); assert_eq!(parse_pi(b">?>", true), Ok(0)); }