pub(crate) const JS_WHITESPACE: [char; 25] = [
'\u{9}', '\u{a}', '\u{b}', '\u{c}', '\u{d}', '\u{20}', '\u{a0}', '\u{1680}', '\u{2000}', '\u{2001}', '\u{2002}', '\u{2003}', '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}',
'\u{2008}', '\u{2009}', '\u{200a}', '\u{2028}', '\u{2029}', '\u{202f}', '\u{205f}', '\u{3000}', '\u{feff}', ];
pub(crate) fn is_js_whitespace(c: char) -> bool {
JS_WHITESPACE.contains(&c)
}
pub(crate) fn trim(value: &str) -> &str {
value.trim_matches(is_js_whitespace)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_byte_order_mark_is_whitespace_here_and_not_in_rust() {
assert!(is_js_whitespace('\u{feff}'));
assert!(!'\u{feff}'.is_whitespace());
assert_eq!(trim("\u{feff}42\u{feff}"), "42");
}
#[test]
fn a_next_line_character_is_whitespace_in_rust_and_not_here() {
assert!(!is_js_whitespace('\u{85}'));
assert!('\u{85}'.is_whitespace());
assert_eq!(trim("\u{85}42"), "\u{85}42");
assert_eq!(trim("42\u{85}"), "42\u{85}");
}
#[test]
fn every_other_character_agrees_with_rusts_whitespace() {
for c in JS_WHITESPACE {
assert_eq!(
c.is_whitespace(),
c != '\u{feff}',
"{c:?} is in JavaScript's set and Rust disagrees"
);
}
for code in 0u32..=0xffff {
let Some(c) = char::from_u32(code) else {
continue;
};
if c.is_whitespace() {
assert_eq!(
is_js_whitespace(c),
c != '\u{85}',
"{c:?} is whitespace in Rust and missing here"
);
}
}
}
#[test]
fn trimming_matches_the_ordinary_cases() {
assert_eq!(trim(" 42 7 "), "42 7");
assert_eq!(trim(""), "");
assert_eq!(trim(" \t\n "), "");
assert_eq!(trim("42"), "42");
}
}