use std::borrow::Cow;
pub fn text(s: &str) -> Cow<'_, str> {
if !s.chars().any(is_unsafe) {
return Cow::Borrowed(s);
}
s.chars()
.map(|c| {
if is_unsafe(c) {
char::REPLACEMENT_CHARACTER
} else {
c
}
})
.collect()
}
fn is_unsafe(c: char) -> bool {
c.is_control() || matches!(c, '\u{202a}'..='\u{202e}' | '\u{2066}'..='\u{2069}')
}
#[cfg(test)]
mod tests {
use std::borrow::Cow;
use crate::sanitize;
#[test]
fn sanitize_borrows_clean_text() {
assert!(matches!(
sanitize::text("Re: café ☕"),
Cow::Borrowed("Re: café ☕")
));
}
#[test]
fn sanitize_replaces_control_characters() {
assert_eq!(
sanitize::text("a\x1b[2Jb\x07c\x7fd\u{9b}e\tf"),
"a�[2Jb�c�d�e�f"
);
}
#[test]
fn sanitize_replaces_bidi_characters() {
assert_eq!(sanitize::text("invoice\u{202e}fdp.exe"), "invoice�fdp.exe");
assert_eq!(sanitize::text("a\u{2066}b\u{2069}c"), "a�b�c");
}
}