use super::Parser;
impl<'a> Parser<'a> {
pub fn take_until_quote(
&mut self,
c_identifier: bool,
max_str_length: usize,
) -> crate::Result<&'a [u8]> {
let start_pos = self.pos;
let input_len = self.input.len();
let max_pos = start_pos.saturating_add(max_str_length + 1); let mut is_first_char = true;
while self.pos < input_len {
if self.pos >= max_pos {
return Err(self.err_max_str_length(max_str_length));
}
let byte = self.input[self.pos];
match byte {
b'"' => {
let slice = &self.input[start_pos..self.pos];
self.pos += 1;
return Ok(slice);
}
b'\\' | b'\t' => {
return Err(self.err_invalid_char(byte as char));
}
b'\n' | b'\r' => {
if c_identifier {
return Err(self.err_invalid_char(byte as char));
}
if byte == b'\n' {
self.line += 1;
}
self.pos += 1;
}
_ => {
if c_identifier {
if is_first_char {
if !(byte.is_ascii_alphabetic() || byte == b'_') {
return Err(self.err_invalid_char(byte as char));
}
is_first_char = false;
} else {
if !(byte.is_ascii_alphanumeric() || byte == b'_') {
return Err(self.err_invalid_char(byte as char));
}
}
} else {
if (byte < 32 && byte != b'\n' && byte != b'\r') || byte == 127 {
return Err(self.err_invalid_char(byte as char));
}
}
self.pos += 1;
}
}
}
Err(self.err_unexpected_eof())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Error;
#[test]
fn take_until_quote_succeeds_with_quote_c_identifier_false() {
let input = b"test\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(false, 256);
assert!(result.is_ok());
let slice = result.unwrap();
assert_eq!(slice, b"test");
assert_eq!(parser.pos, 5); assert_eq!(parser.remaining(), b"rest");
}
#[test]
fn take_until_quote_succeeds_with_c_identifier_true() {
let input = b"test_123\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(true, 256);
assert!(result.is_ok());
let slice = result.unwrap();
assert_eq!(slice, b"test_123");
assert_eq!(parser.pos, 9); }
#[test]
fn take_until_quote_succeeds_c_identifier_underscore_start() {
let input = b"_test123\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(true, 256);
assert!(result.is_ok());
let slice = result.unwrap();
assert_eq!(slice, b"_test123");
}
#[test]
fn take_until_quote_fails_c_identifier_starts_with_digit() {
let input = b"123test\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(true, 256);
assert!(result.is_err());
match result.unwrap_err() {
Error::InvalidChar { char, line } => {
assert_eq!(char, '1');
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::InvalidChar"),
}
}
#[test]
fn take_until_quote_fails_c_identifier_invalid_char() {
let input = b"test-123\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(true, 256);
assert!(result.is_err());
match result.unwrap_err() {
Error::InvalidChar { char, line } => {
assert_eq!(char, '-');
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::InvalidChar"),
}
}
#[test]
fn take_until_quote_succeeds_non_c_identifier_with_special_chars() {
let input = b"test-123!@#\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(false, 256);
assert!(result.is_ok());
let slice = result.unwrap();
assert_eq!(slice, b"test-123!@#");
}
#[test]
fn take_until_quote_fails_with_backslash() {
let input = b"test\\123\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(false, 256);
assert!(result.is_err());
match result.unwrap_err() {
Error::InvalidChar { char, line } => {
assert_eq!(char, '\\');
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::InvalidChar"),
}
}
#[test]
fn take_until_quote_fails_with_tab() {
let input = b"test\t123\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(false, 256);
assert!(result.is_err());
match result.unwrap_err() {
Error::InvalidChar { char, line } => {
assert_eq!(char, '\t');
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::InvalidChar"),
}
}
#[test]
fn take_until_quote_fails_with_newline() {
let input = b"test\n123\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(true, 256);
assert!(result.is_err());
match result.unwrap_err() {
Error::InvalidChar { char, line } => {
assert_eq!(char, '\n');
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::InvalidChar"),
}
}
#[test]
fn take_until_quote_fails_with_carriage_return() {
let input = b"test\r123\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(true, 256);
assert!(result.is_err());
match result.unwrap_err() {
Error::InvalidChar { char, line } => {
assert_eq!(char, '\r');
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::InvalidChar"),
}
}
#[test]
fn take_until_quote_fails_with_eof() {
let input = b"test";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(false, 256);
assert!(result.is_err());
match result.unwrap_err() {
Error::UnexpectedEof { line } => {
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::UnexpectedEof"),
}
}
#[test]
fn take_until_quote_succeeds_empty_string() {
let input = b"\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(false, 256);
assert!(result.is_ok());
let slice = result.unwrap();
assert_eq!(slice, b"");
assert_eq!(parser.pos, 1);
}
#[test]
fn take_until_quote_succeeds_with_printable_chars() {
let input = b"hello world!\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(false, 256);
assert!(result.is_ok());
let slice = result.unwrap();
assert_eq!(slice, b"hello world!");
}
#[test]
fn take_until_quote_fails_when_exceeds_max_length() {
let input = b"a very long string that exceeds the maximum length\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(false, 10);
assert!(result.is_err());
match result.unwrap_err() {
Error::MaxStrLength { max, line } => {
assert_eq!(max, 10);
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::MaxStrLength"),
}
}
#[test]
fn take_until_quote_succeeds_when_at_max_length() {
let input = b"1234567890\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(false, 10);
assert!(result.is_ok());
let slice = result.unwrap();
assert_eq!(slice, b"1234567890");
}
#[test]
fn take_until_quote_fails_when_exceeds_max_length_c_identifier() {
let input = b"very_long_identifier_name_that_exceeds_max\"rest";
let mut parser = Parser::new(input).unwrap();
let result = parser.take_until_quote(true, 20);
assert!(result.is_err());
match result.unwrap_err() {
Error::MaxStrLength { max, line } => {
assert_eq!(max, 20);
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::MaxStrLength"),
}
}
}