use crate::error::{Error, Result};
#[inline]
pub fn unescape_string_optimized(s: &str) -> Result<String> {
if !s.contains('\\') {
return Ok(s.to_string());
}
let mut result = String::with_capacity(s.len()); let mut chars = s.chars();
while let Some(ch) = chars.next() {
if ch == '\\' {
match chars.next() {
Some('n') => result.push('\n'),
Some('t') => result.push('\t'),
Some('r') => result.push('\r'),
Some('\\') => result.push('\\'),
Some('"') => result.push('"'),
Some('\'') => result.push('\''),
Some('/') => result.push('/'),
Some('b') => result.push('\x08'),
Some('f') => result.push('\x0C'),
Some('u') => {
result.push(parse_unicode_escape(&mut chars)?);
}
Some('x') => {
result.push(parse_hex_escape(&mut chars)?);
}
Some(other) => {
result.push('\\');
result.push(other);
}
None => result.push('\\'),
}
} else {
result.push(ch);
}
}
Ok(result)
}
#[inline]
fn parse_unicode_escape(chars: &mut std::str::Chars<'_>) -> Result<char> {
let mut code = 0u32;
for _ in 0..4 {
let hex_char = chars.next().ok_or(Error::InvalidEscape(0))?;
let digit = hex_char.to_digit(16).ok_or(Error::InvalidEscape(0))?;
code = (code << 4) | digit;
}
if let Some(next_char) = chars.clone().next() {
if next_char.is_ascii_hexdigit() {
return Err(Error::InvalidEscape(0));
}
}
std::char::from_u32(code).ok_or(Error::InvalidUnicode(0))
}
#[inline]
fn parse_hex_escape(chars: &mut std::str::Chars<'_>) -> Result<char> {
let mut code = 0u8;
for _ in 0..2 {
let hex_char = chars.next().ok_or(Error::InvalidEscape(0))?;
let digit = hex_char.to_digit(16).ok_or(Error::InvalidEscape(0))? as u8;
code = (code << 4) | digit;
}
Ok(code as char)
}
#[inline]
pub fn extract_string_content(slice: &str) -> Result<&str> {
if slice.len() < 2 {
return Err(Error::UnterminatedString(0));
}
let first = slice.as_bytes()[0];
let last = slice.as_bytes()[slice.len() - 1];
if (first == b'"' && last == b'"') || (first == b'\'' && last == b'\'') {
Ok(&slice[1..slice.len() - 1])
} else {
Err(Error::UnterminatedString(0))
}
}
#[inline]
pub fn parse_number_optimized(s: &str) -> Result<f64> {
if !s.contains('.') && !s.contains('e') && !s.contains('E') {
if let Ok(int_val) = s.parse::<i64>() {
return Ok(int_val as f64);
}
}
s.parse::<f64>().map_err(|_| Error::InvalidNumber(0))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_unescape_no_escapes() {
let result = unescape_string_optimized("hello world").unwrap();
assert_eq!(result, "hello world");
}
#[test]
fn test_unescape_with_escapes() {
let result = unescape_string_optimized("hello\\nworld\\t!").unwrap();
assert_eq!(result, "hello\nworld\t!");
}
#[test]
fn test_extract_string_content() {
assert_eq!(extract_string_content("\"hello\"").unwrap(), "hello");
assert_eq!(extract_string_content("'world'").unwrap(), "world");
}
#[test]
fn test_parse_number_optimized() {
assert_eq!(parse_number_optimized("42").unwrap(), 42.0);
assert_eq!(parse_number_optimized("3.14").unwrap(), 3.14);
assert_eq!(parse_number_optimized("-123").unwrap(), -123.0);
}
}