use std::borrow::Cow;
use std::fmt;
use std::str;
#[must_use]
pub(crate) fn escape_log_control_characters<'a>(value: Cow<'a, str>) -> Cow<'a, str> {
let Some((index, first_unsafe)) = value
.char_indices()
.find(|(_, character)| is_log_unsafe_character(*character))
else {
return value;
};
let mut escaped = String::with_capacity(value.len());
escaped.push_str(&value[..index]);
escaped.extend(first_unsafe.escape_debug());
for character in value[index + first_unsafe.len_utf8()..].chars() {
if is_log_unsafe_character(character) {
escaped.extend(character.escape_debug());
} else {
escaped.push(character);
}
}
Cow::Owned(escaped)
}
#[must_use]
#[inline]
pub(crate) fn is_log_unsafe_character(character: char) -> bool {
character.is_control()
|| matches!(
character,
'\u{061c}'
| '\u{200e}'
| '\u{200f}'
| '\u{2028}'..='\u{202e}'
| '\u{2066}'..='\u{2069}'
)
}
pub(crate) fn encode_log_safe_character(character: char, buffer: &mut [u8; 12]) -> Result<&str, fmt::Error> {
let length = if is_log_unsafe_character(character) {
let mut length = 0;
for escaped in character.escape_debug() {
let encoded = escaped.encode_utf8(&mut buffer[length..]);
length += encoded.len();
}
length
} else {
character.encode_utf8(buffer).len()
};
str::from_utf8(&buffer[..length]).map_err(|_| fmt::Error)
}