pub(crate) const MIN_EVASION_DECODE_LEN: usize = 16;
pub(crate) fn simple_control_escape(escaped: char) -> Option<char> {
match escaped {
'b' => Some('\x08'),
'f' => Some('\x0c'),
'n' => Some('\n'),
'r' => Some('\r'),
't' => Some('\t'),
_ => None,
}
}
#[allow(clippy::result_unit_err)]
pub(crate) fn take_hex_digits<I>(chars: &mut I, count: usize) -> Result<u32, ()>
where
I: Iterator<Item = char>,
{
let mut value = 0u32;
for _ in 0..count {
let ch = chars.next().ok_or(())?;
value = (value << 4) | ch.to_digit(16).ok_or(())?;
}
Ok(value)
}
#[allow(clippy::result_unit_err)]
pub(crate) fn take_hex_digits_indexed<I>(chars: &mut I, count: usize) -> Result<u32, ()>
where
I: Iterator<Item = (usize, char)>,
{
take_hex_digits(&mut chars.map(|(_, c)| c), count)
}
#[allow(clippy::result_unit_err)]
pub(crate) fn resolve_escaped_codepoint<I>(code: u32, chars: &mut I) -> Result<char, ()>
where
I: Iterator<Item = char>,
{
if (0xD800..=0xDBFF).contains(&code) {
match (chars.next(), chars.next()) {
(Some('\\'), Some('u')) => {}
_ => return Err(()),
}
let low = take_hex_digits(chars, 4)?;
if !(0xDC00..=0xDFFF).contains(&low) {
return Err(());
}
return surrogate_pair_to_char(code, low).ok_or(());
}
if (0xDC00..=0xDFFF).contains(&code) {
return Err(());
}
char::from_u32(code).ok_or(())
}
pub(super) fn lazy_decoded_prefix<'a>(
decoded: &'a mut Option<String>,
input: &str,
prefix_end: usize,
) -> &'a mut String {
decoded.get_or_insert_with(|| {
let mut out = String::with_capacity(input.len());
out.push_str(&input[..prefix_end]);
out
})
}
pub(crate) fn surrogate_pair_to_char(high: u32, low: u32) -> Option<char> {
let scalar = 0x10000 + (((high - 0xD800) << 10) | (low - 0xDC00));
char::from_u32(scalar)
}
#[allow(clippy::result_unit_err)]
pub(crate) fn hex_val(byte: u8) -> Result<u8, ()> {
match byte {
b'0'..=b'9' => Ok(byte - b'0'),
b'a'..=b'f' => Ok(byte - b'a' + 10),
b'A'..=b'F' => Ok(byte - b'A' + 10),
_ => Err(()),
}
}