use alloc::borrow::Cow;
use alloc::string::String;
use unicode_normalization::{IsNormalized, UnicodeNormalization, is_nfc_quick};
pub(crate) fn is_nfc(s: &str) -> bool {
s.bytes().all(|b| b < 0xCC) || is_nfc_quick(s.chars()) == IsNormalized::Yes
}
pub(crate) fn nfc_eq(a: &str, b: &str) -> bool {
if a == b {
return true;
}
if is_nfc(a) && is_nfc(b) {
return false;
}
a.nfc().eq(b.nfc())
}
pub(crate) fn nfc(s: &str) -> Cow<'_, str> {
if is_nfc(s) {
Cow::Borrowed(s)
} else {
Cow::Owned(s.nfc().collect::<String>())
}
}
#[cfg(test)]
mod tests {
use alloc::borrow::Cow;
use super::{is_nfc, nfc, nfc_eq};
#[test]
fn equivalence() {
assert!(nfc_eq("\u{1E0C}\u{307}", "D\u{323}\u{307}"));
assert!(nfc_eq("\u{1E0A}\u{323}", "\u{1E0C}\u{307}"));
assert!(nfc_eq("D\u{307}\u{323}", "\u{1E0C}\u{307}"));
assert!(nfc_eq("A\u{30A}\u{301}", "\u{1FA}"));
assert!(!nfc_eq("a", "b"));
assert!(!nfc_eq("\u{e9}", "e"));
assert!(nfc_eq("", ""));
}
#[test]
fn quick_check_and_normalization() {
assert!(is_nfc("plain ascii"));
assert!(is_nfc("\u{e9}t\u{e9}"));
assert!(!is_nfc("e\u{301}"));
assert!(matches!(nfc("abc"), Cow::Borrowed("abc")));
assert_eq!(nfc("e\u{301}"), "\u{e9}");
assert_eq!(nfc("D\u{323}\u{307}"), "\u{1E0C}\u{307}");
}
}