#[cfg(feature = "tracing-recover")]
use crate::utils::bytes_to_trace_string;
use nom::{
character::complete::{space0, space1},
error::{Error, ErrorKind},
Err, IResult,
};
use std::borrow::Cow;
#[cfg(feature = "tracing-recover")]
use tracing::warn;
pub fn take_utf8_while1<F>(cond: F) -> impl Fn(&[u8]) -> IResult<&[u8], Cow<'_, str>>
where
F: Fn(char) -> bool,
{
move |i: &[u8]| {
let mut it = utf8_iter::ErrorReportingUtf8Chars::new(i);
let i_len = i.len();
let mut rest = i;
loop {
match it.next() {
Some(Ok(c)) if cond(c) => {
rest = it.as_slice();
}
Some(Err(_)) => {
break;
}
_ => {
let end = i_len - rest.len();
if end > 0 {
let sub = unsafe { str::from_utf8_unchecked(&i[0..end]) };
return Ok((rest, Cow::Borrowed(sub)));
} else {
return Err(Err::Error(Error {
input: i,
code: ErrorKind::TakeWhile1,
}));
}
}
}
}
#[cfg(feature = "tracing-recover")]
warn!(input = %bytes_to_trace_string(i), "input contains invalid UTF-8");
let mut s = String::new();
s.push_str(unsafe { str::from_utf8_unchecked(&i[0..i_len - rest.len()]) });
s.push(char::REPLACEMENT_CHARACTER);
let mut start = i_len - it.as_slice().len();
let mut rest = it.as_slice();
loop {
match it.next() {
Some(Ok(c)) if cond(c) => {
rest = it.as_slice();
}
res => {
let end = i_len - rest.len();
s.push_str(unsafe { str::from_utf8_unchecked(&i[start..end]) });
if let Some(Err(_)) = res {
s.push(char::REPLACEMENT_CHARACTER);
start = i_len - it.as_slice().len();
rest = it.as_slice();
} else {
break;
}
}
}
}
if !s.is_empty() {
Ok((rest, Cow::Owned(s)))
} else {
Err(Err::Error(Error {
input: i,
code: ErrorKind::TakeWhile1,
}))
}
}
}
pub fn is_nonascii_or<F>(cond: F) -> impl Fn(char) -> bool
where
F: Fn(u8) -> bool,
{
move |c: char| {
if c.is_ascii() {
let c = u8::try_from(c).unwrap();
cond(c)
} else {
true
}
}
}
pub fn is_ascii_and<F>(cond: F) -> impl Fn(char) -> bool
where
F: Fn(u8) -> bool,
{
move |c: char| {
if c.is_ascii() {
let c = u8::try_from(c).unwrap();
cond(c)
} else {
false
}
}
}
pub fn space0_str(input: &[u8]) -> nom::IResult<&[u8], &str> {
let (input, sp) = space0(input)?;
Ok((input, unsafe { str::from_utf8_unchecked(sp) }))
}
pub fn space1_str(input: &[u8]) -> nom::IResult<&[u8], &str> {
let (input, sp) = space1(input)?;
Ok((input, unsafe { str::from_utf8_unchecked(sp) }))
}