Skip to main content

radixdb_core/
unicode.rs

1//! Small Unicode primitives shared by format-owning crates.
2
3use unicode_normalization::UnicodeNormalization;
4
5/// Return canonical NFC text without changing Unicode case.
6pub fn canonical_unicode_nfc(value: &str) -> String {
7    value.nfc().collect()
8}
9
10/// Return canonical NFC Unicode lowercase text.
11///
12/// Lowercasing can itself introduce combining code points, so NFC is applied
13/// both before and after Unicode lowercase expansion. This is not locale-aware
14/// case folding; it is the stable naming rule used by persisted contracts.
15pub fn canonical_unicode_lowercase_nfc(value: &str) -> String {
16    canonical_unicode_nfc(value)
17        .chars()
18        .flat_map(char::to_lowercase)
19        .collect::<String>()
20        .nfc()
21        .collect()
22}
23
24#[cfg(test)]
25mod tests {
26    use super::*;
27
28    #[test]
29    fn canonicalizes_composed_case_equivalents() {
30        assert_eq!(canonical_unicode_nfc("CAF\u{45}\u{301}"), "CAFÉ");
31        assert_eq!(canonical_unicode_lowercase_nfc("CAF\u{45}\u{301}"), "café");
32        assert_eq!(canonical_unicode_lowercase_nfc("CAFÉ"), "café");
33    }
34
35    #[test]
36    fn normalizes_lowercase_expansion_output() {
37        assert_eq!(canonical_unicode_lowercase_nfc("İ"), "i\u{307}");
38    }
39}