use std::borrow::Cow;
use unicode_normalization::{UnicodeNormalization, IsNormalized, is_nfc, is_nfc_quick};
pub(crate) fn normalize(word: String) -> String {
if let Cow::Owned(normalized) = normalize_if_needed(&word) {
normalized
} else {
word
}
}
pub(crate) fn normalize_if_needed(word: &str) -> Cow<str> {
if is_normalized(word) {
Cow::Borrowed(word)
} else {
Cow::Owned(word.nfc().collect::<String>())
}
}
pub(crate) fn is_normalized(word: &str) -> bool {
match is_nfc_quick(word.chars()) {
IsNormalized::Yes => true,
IsNormalized::No => false,
IsNormalized::Maybe => is_nfc(&word),
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_is_normalized() {
let nfc = "cornū".nfc().collect::<String>();
let nfd = "cornū".nfd().collect::<String>();
assert!(is_normalized(&nfc), "is_normalized returned false for a string that is in NFC form.");
assert_eq!(is_normalized(&nfd), false, "is_normalized returned true for a string that is not in NFC form.");
}
#[test]
fn test_normalize_if_needed() {
let nfc = "cornū".nfc().collect::<String>();
let nfd = "cornū".nfd().collect::<String>();
match normalize_if_needed(&nfc) {
Cow::Borrowed(normalized) => {
if is_nfc(normalized) == false {
panic!("normalized(&nfc) returned a string that wasn't in NFC form.")
}
},
Cow::Owned(_) => panic!("normalize returned a Cow::Owned for a string that is in NFC form."),
}
match normalize_if_needed(&nfd) {
Cow::Owned(normalized) => {
if is_nfc(&normalized) == false {
panic!("normalized(&nfd) returned a string that wasn't in NFC form.")
}
},
Cow::Borrowed(_) => panic!("normalize returned a Cow::Borrowed for a string that is in NFD form."),
}
}
#[test]
fn test_normalize() {
let nfd = "cornū".nfd().collect::<String>();
let nfc = normalize(nfd);
if is_nfc(&nfc) == false {
panic!("String returned by normalize is not in NFC form.")
}
}
}