/src/unicode-normalization/src/quick_check.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use crate::lookups::canonical_combining_class; |
2 | | use crate::stream_safe; |
3 | | use crate::tables; |
4 | | use crate::UnicodeNormalization; |
5 | | |
6 | | /// QuickCheck quickly determines if a string is normalized, it can return |
7 | | /// `Maybe` |
8 | | /// |
9 | | /// The QuickCheck algorithm can quickly determine if a text is or isn't |
10 | | /// normalized without any allocations in many cases, but it has to be able to |
11 | | /// return `Maybe` when a full decomposition and recomposition is necessary. |
12 | | #[derive(Debug, Eq, PartialEq)] |
13 | | pub enum IsNormalized { |
14 | | /// The text is definitely normalized. |
15 | | Yes, |
16 | | /// The text is definitely not normalized. |
17 | | No, |
18 | | /// The text may be normalized. |
19 | | Maybe, |
20 | | } |
21 | | |
22 | | // https://unicode.org/reports/tr15/#Detecting_Normalization_Forms |
23 | | #[inline] |
24 | 154k | fn quick_check<F, I>(s: I, is_allowed: F, stream_safe: bool) -> IsNormalized |
25 | 154k | where |
26 | 154k | I: Iterator<Item = char>, |
27 | 154k | F: Fn(char) -> IsNormalized, |
28 | 154k | { |
29 | 154k | let mut last_cc = 0u8; |
30 | 154k | let mut nonstarter_count = 0; |
31 | 154k | let mut result = IsNormalized::Yes; |
32 | 314M | for ch in s { |
33 | | // For ASCII we know it's always allowed and a starter |
34 | 313M | if ch <= '\x7f' { |
35 | 102M | last_cc = 0; |
36 | 102M | nonstarter_count = 0; |
37 | 102M | continue; |
38 | 211M | } |
39 | 211M | |
40 | 211M | // Otherwise, lookup the combining class and QC property |
41 | 211M | let cc = canonical_combining_class(ch); |
42 | 211M | if last_cc > cc && cc != 0 { |
43 | 1.49k | return IsNormalized::No; |
44 | 211M | } |
45 | 211M | match is_allowed(ch) { |
46 | 134M | IsNormalized::Yes => (), |
47 | 26.1k | IsNormalized::No => return IsNormalized::No, |
48 | 76.2M | IsNormalized::Maybe => { |
49 | 76.2M | result = IsNormalized::Maybe; |
50 | 76.2M | } |
51 | | } |
52 | 211M | if stream_safe { |
53 | 91.2M | let decomp = stream_safe::classify_nonstarters(ch); |
54 | 91.2M | |
55 | 91.2M | // If we're above `MAX_NONSTARTERS`, we're definitely *not* |
56 | 91.2M | // stream-safe normalized. |
57 | 91.2M | if nonstarter_count + decomp.leading_nonstarters > stream_safe::MAX_NONSTARTERS { |
58 | 1.37k | return IsNormalized::No; |
59 | 91.2M | } |
60 | 91.2M | if decomp.leading_nonstarters == decomp.decomposition_len { |
61 | 78.9M | nonstarter_count += decomp.decomposition_len; |
62 | 78.9M | } else { |
63 | 12.3M | nonstarter_count = decomp.trailing_nonstarters; |
64 | 12.3M | } |
65 | 119M | } |
66 | 211M | last_cc = cc; |
67 | | } |
68 | 125k | result |
69 | 154k | } unicode_normalization::quick_check::quick_check::<unicode_normalization::tables::qc_nfc, core::str::iter::Chars> Line | Count | Source | 24 | 55.1k | fn quick_check<F, I>(s: I, is_allowed: F, stream_safe: bool) -> IsNormalized | 25 | 55.1k | where | 26 | 55.1k | I: Iterator<Item = char>, | 27 | 55.1k | F: Fn(char) -> IsNormalized, | 28 | 55.1k | { | 29 | 55.1k | let mut last_cc = 0u8; | 30 | 55.1k | let mut nonstarter_count = 0; | 31 | 55.1k | let mut result = IsNormalized::Yes; | 32 | 101M | for ch in s { | 33 | | // For ASCII we know it's always allowed and a starter | 34 | 101M | if ch <= '\x7f' { | 35 | 34.0M | last_cc = 0; | 36 | 34.0M | nonstarter_count = 0; | 37 | 34.0M | continue; | 38 | 67.4M | } | 39 | 67.4M | | 40 | 67.4M | // Otherwise, lookup the combining class and QC property | 41 | 67.4M | let cc = canonical_combining_class(ch); | 42 | 67.4M | if last_cc > cc && cc != 0 { | 43 | 564 | return IsNormalized::No; | 44 | 67.4M | } | 45 | 67.4M | match is_allowed(ch) { | 46 | 10.2M | IsNormalized::Yes => (), | 47 | 5.26k | IsNormalized::No => return IsNormalized::No, | 48 | 57.1M | IsNormalized::Maybe => { | 49 | 57.1M | result = IsNormalized::Maybe; | 50 | 57.1M | } | 51 | | } | 52 | 67.4M | if stream_safe { | 53 | 45.0M | let decomp = stream_safe::classify_nonstarters(ch); | 54 | 45.0M | | 55 | 45.0M | // If we're above `MAX_NONSTARTERS`, we're definitely *not* | 56 | 45.0M | // stream-safe normalized. | 57 | 45.0M | if nonstarter_count + decomp.leading_nonstarters > stream_safe::MAX_NONSTARTERS { | 58 | 746 | return IsNormalized::No; | 59 | 45.0M | } | 60 | 45.0M | if decomp.leading_nonstarters == decomp.decomposition_len { | 61 | 38.4M | nonstarter_count += decomp.decomposition_len; | 62 | 38.4M | } else { | 63 | 6.59M | nonstarter_count = decomp.trailing_nonstarters; | 64 | 6.59M | } | 65 | 22.3M | } | 66 | 67.4M | last_cc = cc; | 67 | | } | 68 | 48.5k | result | 69 | 55.1k | } |
unicode_normalization::quick_check::quick_check::<unicode_normalization::tables::qc_nfd, core::str::iter::Chars> Line | Count | Source | 24 | 55.1k | fn quick_check<F, I>(s: I, is_allowed: F, stream_safe: bool) -> IsNormalized | 25 | 55.1k | where | 26 | 55.1k | I: Iterator<Item = char>, | 27 | 55.1k | F: Fn(char) -> IsNormalized, | 28 | 55.1k | { | 29 | 55.1k | let mut last_cc = 0u8; | 30 | 55.1k | let mut nonstarter_count = 0; | 31 | 55.1k | let mut result = IsNormalized::Yes; | 32 | 102M | for ch in s { | 33 | | // For ASCII we know it's always allowed and a starter | 34 | 102M | if ch <= '\x7f' { | 35 | 33.9M | last_cc = 0; | 36 | 33.9M | nonstarter_count = 0; | 37 | 33.9M | continue; | 38 | 68.8M | } | 39 | 68.8M | | 40 | 68.8M | // Otherwise, lookup the combining class and QC property | 41 | 68.8M | let cc = canonical_combining_class(ch); | 42 | 68.8M | if last_cc > cc && cc != 0 { | 43 | 458 | return IsNormalized::No; | 44 | 68.8M | } | 45 | 68.8M | match is_allowed(ch) { | 46 | 68.7M | IsNormalized::Yes => (), | 47 | 9.63k | IsNormalized::No => return IsNormalized::No, | 48 | 0 | IsNormalized::Maybe => { | 49 | 0 | result = IsNormalized::Maybe; | 50 | 0 | } | 51 | | } | 52 | 68.7M | if stream_safe { | 53 | 46.2M | let decomp = stream_safe::classify_nonstarters(ch); | 54 | 46.2M | | 55 | 46.2M | // If we're above `MAX_NONSTARTERS`, we're definitely *not* | 56 | 46.2M | // stream-safe normalized. | 57 | 46.2M | if nonstarter_count + decomp.leading_nonstarters > stream_safe::MAX_NONSTARTERS { | 58 | 628 | return IsNormalized::No; | 59 | 46.2M | } | 60 | 46.2M | if decomp.leading_nonstarters == decomp.decomposition_len { | 61 | 40.5M | nonstarter_count += decomp.decomposition_len; | 62 | 40.5M | } else { | 63 | 5.73M | nonstarter_count = decomp.trailing_nonstarters; | 64 | 5.73M | } | 65 | 22.5M | } | 66 | 68.7M | last_cc = cc; | 67 | | } | 68 | 44.4k | result | 69 | 55.1k | } |
unicode_normalization::quick_check::quick_check::<unicode_normalization::tables::qc_nfkc, core::str::iter::Chars> Line | Count | Source | 24 | 22.0k | fn quick_check<F, I>(s: I, is_allowed: F, stream_safe: bool) -> IsNormalized | 25 | 22.0k | where | 26 | 22.0k | I: Iterator<Item = char>, | 27 | 22.0k | F: Fn(char) -> IsNormalized, | 28 | 22.0k | { | 29 | 22.0k | let mut last_cc = 0u8; | 30 | 22.0k | let mut nonstarter_count = 0; | 31 | 22.0k | let mut result = IsNormalized::Yes; | 32 | 53.6M | for ch in s { | 33 | | // For ASCII we know it's always allowed and a starter | 34 | 53.6M | if ch <= '\x7f' { | 35 | 17.4M | last_cc = 0; | 36 | 17.4M | nonstarter_count = 0; | 37 | 17.4M | continue; | 38 | 36.1M | } | 39 | 36.1M | | 40 | 36.1M | // Otherwise, lookup the combining class and QC property | 41 | 36.1M | let cc = canonical_combining_class(ch); | 42 | 36.1M | if last_cc > cc && cc != 0 { | 43 | 256 | return IsNormalized::No; | 44 | 36.1M | } | 45 | 36.1M | match is_allowed(ch) { | 46 | 17.1M | IsNormalized::Yes => (), | 47 | 4.72k | IsNormalized::No => return IsNormalized::No, | 48 | 19.0M | IsNormalized::Maybe => { | 49 | 19.0M | result = IsNormalized::Maybe; | 50 | 19.0M | } | 51 | | } | 52 | 36.1M | if stream_safe { | 53 | 0 | let decomp = stream_safe::classify_nonstarters(ch); | 54 | 0 |
| 55 | 0 | // If we're above `MAX_NONSTARTERS`, we're definitely *not* | 56 | 0 | // stream-safe normalized. | 57 | 0 | if nonstarter_count + decomp.leading_nonstarters > stream_safe::MAX_NONSTARTERS { | 58 | 0 | return IsNormalized::No; | 59 | 0 | } | 60 | 0 | if decomp.leading_nonstarters == decomp.decomposition_len { | 61 | 0 | nonstarter_count += decomp.decomposition_len; | 62 | 0 | } else { | 63 | 0 | nonstarter_count = decomp.trailing_nonstarters; | 64 | 0 | } | 65 | 36.1M | } | 66 | 36.1M | last_cc = cc; | 67 | | } | 68 | 17.0k | result | 69 | 22.0k | } |
unicode_normalization::quick_check::quick_check::<unicode_normalization::tables::qc_nfkd, core::str::iter::Chars> Line | Count | Source | 24 | 22.0k | fn quick_check<F, I>(s: I, is_allowed: F, stream_safe: bool) -> IsNormalized | 25 | 22.0k | where | 26 | 22.0k | I: Iterator<Item = char>, | 27 | 22.0k | F: Fn(char) -> IsNormalized, | 28 | 22.0k | { | 29 | 22.0k | let mut last_cc = 0u8; | 30 | 22.0k | let mut nonstarter_count = 0; | 31 | 22.0k | let mut result = IsNormalized::Yes; | 32 | 56.0M | for ch in s { | 33 | | // For ASCII we know it's always allowed and a starter | 34 | 56.0M | if ch <= '\x7f' { | 35 | 17.3M | last_cc = 0; | 36 | 17.3M | nonstarter_count = 0; | 37 | 17.3M | continue; | 38 | 38.6M | } | 39 | 38.6M | | 40 | 38.6M | // Otherwise, lookup the combining class and QC property | 41 | 38.6M | let cc = canonical_combining_class(ch); | 42 | 38.6M | if last_cc > cc && cc != 0 { | 43 | 214 | return IsNormalized::No; | 44 | 38.6M | } | 45 | 38.6M | match is_allowed(ch) { | 46 | 38.6M | IsNormalized::Yes => (), | 47 | 6.49k | IsNormalized::No => return IsNormalized::No, | 48 | 0 | IsNormalized::Maybe => { | 49 | 0 | result = IsNormalized::Maybe; | 50 | 0 | } | 51 | | } | 52 | 38.6M | if stream_safe { | 53 | 0 | let decomp = stream_safe::classify_nonstarters(ch); | 54 | 0 |
| 55 | 0 | // If we're above `MAX_NONSTARTERS`, we're definitely *not* | 56 | 0 | // stream-safe normalized. | 57 | 0 | if nonstarter_count + decomp.leading_nonstarters > stream_safe::MAX_NONSTARTERS { | 58 | 0 | return IsNormalized::No; | 59 | 0 | } | 60 | 0 | if decomp.leading_nonstarters == decomp.decomposition_len { | 61 | 0 | nonstarter_count += decomp.decomposition_len; | 62 | 0 | } else { | 63 | 0 | nonstarter_count = decomp.trailing_nonstarters; | 64 | 0 | } | 65 | 38.6M | } | 66 | 38.6M | last_cc = cc; | 67 | | } | 68 | 15.3k | result | 69 | 22.0k | } |
Unexecuted instantiation: unicode_normalization::quick_check::quick_check::<_, _> |
70 | | |
71 | | /// Quickly check if a string is in NFC, potentially returning |
72 | | /// `IsNormalized::Maybe` if further checks are necessary. In this case a check |
73 | | /// like `s.chars().nfc().eq(s.chars())` should suffice. |
74 | | #[inline] |
75 | 22.0k | pub fn is_nfc_quick<I: Iterator<Item = char>>(s: I) -> IsNormalized { |
76 | 22.0k | quick_check(s, tables::qc_nfc, false) |
77 | 22.0k | } unicode_normalization::quick_check::is_nfc_quick::<core::str::iter::Chars> Line | Count | Source | 75 | 22.0k | pub fn is_nfc_quick<I: Iterator<Item = char>>(s: I) -> IsNormalized { | 76 | 22.0k | quick_check(s, tables::qc_nfc, false) | 77 | 22.0k | } |
Unexecuted instantiation: unicode_normalization::quick_check::is_nfc_quick::<_> |
78 | | |
79 | | /// Quickly check if a string is in NFKC. |
80 | | #[inline] |
81 | 22.0k | pub fn is_nfkc_quick<I: Iterator<Item = char>>(s: I) -> IsNormalized { |
82 | 22.0k | quick_check(s, tables::qc_nfkc, false) |
83 | 22.0k | } unicode_normalization::quick_check::is_nfkc_quick::<core::str::iter::Chars> Line | Count | Source | 81 | 22.0k | pub fn is_nfkc_quick<I: Iterator<Item = char>>(s: I) -> IsNormalized { | 82 | 22.0k | quick_check(s, tables::qc_nfkc, false) | 83 | 22.0k | } |
Unexecuted instantiation: unicode_normalization::quick_check::is_nfkc_quick::<_> |
84 | | |
85 | | /// Quickly check if a string is in NFD. |
86 | | #[inline] |
87 | 22.0k | pub fn is_nfd_quick<I: Iterator<Item = char>>(s: I) -> IsNormalized { |
88 | 22.0k | quick_check(s, tables::qc_nfd, false) |
89 | 22.0k | } unicode_normalization::quick_check::is_nfd_quick::<core::str::iter::Chars> Line | Count | Source | 87 | 22.0k | pub fn is_nfd_quick<I: Iterator<Item = char>>(s: I) -> IsNormalized { | 88 | 22.0k | quick_check(s, tables::qc_nfd, false) | 89 | 22.0k | } |
Unexecuted instantiation: unicode_normalization::quick_check::is_nfd_quick::<_> |
90 | | |
91 | | /// Quickly check if a string is in NFKD. |
92 | | #[inline] |
93 | 22.0k | pub fn is_nfkd_quick<I: Iterator<Item = char>>(s: I) -> IsNormalized { |
94 | 22.0k | quick_check(s, tables::qc_nfkd, false) |
95 | 22.0k | } unicode_normalization::quick_check::is_nfkd_quick::<core::str::iter::Chars> Line | Count | Source | 93 | 22.0k | pub fn is_nfkd_quick<I: Iterator<Item = char>>(s: I) -> IsNormalized { | 94 | 22.0k | quick_check(s, tables::qc_nfkd, false) | 95 | 22.0k | } |
Unexecuted instantiation: unicode_normalization::quick_check::is_nfkd_quick::<_> |
96 | | |
97 | | /// Quickly check if a string is Stream-Safe NFC. |
98 | | #[inline] |
99 | 33.0k | pub fn is_nfc_stream_safe_quick<I: Iterator<Item = char>>(s: I) -> IsNormalized { |
100 | 33.0k | quick_check(s, tables::qc_nfc, true) |
101 | 33.0k | } unicode_normalization::quick_check::is_nfc_stream_safe_quick::<core::str::iter::Chars> Line | Count | Source | 99 | 33.0k | pub fn is_nfc_stream_safe_quick<I: Iterator<Item = char>>(s: I) -> IsNormalized { | 100 | 33.0k | quick_check(s, tables::qc_nfc, true) | 101 | 33.0k | } |
Unexecuted instantiation: unicode_normalization::quick_check::is_nfc_stream_safe_quick::<_> |
102 | | |
103 | | /// Quickly check if a string is Stream-Safe NFD. |
104 | | #[inline] |
105 | 33.0k | pub fn is_nfd_stream_safe_quick<I: Iterator<Item = char>>(s: I) -> IsNormalized { |
106 | 33.0k | quick_check(s, tables::qc_nfd, true) |
107 | 33.0k | } unicode_normalization::quick_check::is_nfd_stream_safe_quick::<core::str::iter::Chars> Line | Count | Source | 105 | 33.0k | pub fn is_nfd_stream_safe_quick<I: Iterator<Item = char>>(s: I) -> IsNormalized { | 106 | 33.0k | quick_check(s, tables::qc_nfd, true) | 107 | 33.0k | } |
Unexecuted instantiation: unicode_normalization::quick_check::is_nfd_stream_safe_quick::<_> |
108 | | |
109 | | /// Authoritatively check if a string is in NFC. |
110 | | #[inline] |
111 | 11.0k | pub fn is_nfc(s: &str) -> bool { |
112 | 11.0k | match is_nfc_quick(s.chars()) { |
113 | 6.01k | IsNormalized::Yes => true, |
114 | 1.51k | IsNormalized::No => false, |
115 | 3.50k | IsNormalized::Maybe => s.chars().eq(s.chars().nfc()), |
116 | | } |
117 | 11.0k | } unicode_normalization::quick_check::is_nfc Line | Count | Source | 111 | 11.0k | pub fn is_nfc(s: &str) -> bool { | 112 | 11.0k | match is_nfc_quick(s.chars()) { | 113 | 6.01k | IsNormalized::Yes => true, | 114 | 1.51k | IsNormalized::No => false, | 115 | 3.50k | IsNormalized::Maybe => s.chars().eq(s.chars().nfc()), | 116 | | } | 117 | 11.0k | } |
Unexecuted instantiation: unicode_normalization::quick_check::is_nfc |
118 | | |
119 | | /// Authoritatively check if a string is in NFKC. |
120 | | #[inline] |
121 | 11.0k | pub fn is_nfkc(s: &str) -> bool { |
122 | 11.0k | match is_nfkc_quick(s.chars()) { |
123 | 5.15k | IsNormalized::Yes => true, |
124 | 2.48k | IsNormalized::No => false, |
125 | 3.38k | IsNormalized::Maybe => s.chars().eq(s.chars().nfkc()), |
126 | | } |
127 | 11.0k | } unicode_normalization::quick_check::is_nfkc Line | Count | Source | 121 | 11.0k | pub fn is_nfkc(s: &str) -> bool { | 122 | 11.0k | match is_nfkc_quick(s.chars()) { | 123 | 5.15k | IsNormalized::Yes => true, | 124 | 2.48k | IsNormalized::No => false, | 125 | 3.38k | IsNormalized::Maybe => s.chars().eq(s.chars().nfkc()), | 126 | | } | 127 | 11.0k | } |
Unexecuted instantiation: unicode_normalization::quick_check::is_nfkc |
128 | | |
129 | | /// Authoritatively check if a string is in NFD. |
130 | | #[inline] |
131 | 11.0k | pub fn is_nfd(s: &str) -> bool { |
132 | 11.0k | match is_nfd_quick(s.chars()) { |
133 | 8.37k | IsNormalized::Yes => true, |
134 | 2.65k | IsNormalized::No => false, |
135 | 0 | IsNormalized::Maybe => s.chars().eq(s.chars().nfd()), |
136 | | } |
137 | 11.0k | } unicode_normalization::quick_check::is_nfd Line | Count | Source | 131 | 11.0k | pub fn is_nfd(s: &str) -> bool { | 132 | 11.0k | match is_nfd_quick(s.chars()) { | 133 | 8.37k | IsNormalized::Yes => true, | 134 | 2.65k | IsNormalized::No => false, | 135 | 0 | IsNormalized::Maybe => s.chars().eq(s.chars().nfd()), | 136 | | } | 137 | 11.0k | } |
Unexecuted instantiation: unicode_normalization::quick_check::is_nfd |
138 | | |
139 | | /// Authoritatively check if a string is in NFKD. |
140 | | #[inline] |
141 | 11.0k | pub fn is_nfkd(s: &str) -> bool { |
142 | 11.0k | match is_nfkd_quick(s.chars()) { |
143 | 7.67k | IsNormalized::Yes => true, |
144 | 3.35k | IsNormalized::No => false, |
145 | 0 | IsNormalized::Maybe => s.chars().eq(s.chars().nfkd()), |
146 | | } |
147 | 11.0k | } unicode_normalization::quick_check::is_nfkd Line | Count | Source | 141 | 11.0k | pub fn is_nfkd(s: &str) -> bool { | 142 | 11.0k | match is_nfkd_quick(s.chars()) { | 143 | 7.67k | IsNormalized::Yes => true, | 144 | 3.35k | IsNormalized::No => false, | 145 | 0 | IsNormalized::Maybe => s.chars().eq(s.chars().nfkd()), | 146 | | } | 147 | 11.0k | } |
Unexecuted instantiation: unicode_normalization::quick_check::is_nfkd |
148 | | |
149 | | /// Authoritatively check if a string is Stream-Safe NFC. |
150 | | #[inline] |
151 | 16.5k | pub fn is_nfc_stream_safe(s: &str) -> bool { |
152 | 16.5k | match is_nfc_stream_safe_quick(s.chars()) { |
153 | 9.09k | IsNormalized::Yes => true, |
154 | 1.77k | IsNormalized::No => false, |
155 | 5.67k | IsNormalized::Maybe => s.chars().eq(s.chars().stream_safe().nfc()), |
156 | | } |
157 | 16.5k | } unicode_normalization::quick_check::is_nfc_stream_safe Line | Count | Source | 151 | 16.5k | pub fn is_nfc_stream_safe(s: &str) -> bool { | 152 | 16.5k | match is_nfc_stream_safe_quick(s.chars()) { | 153 | 9.09k | IsNormalized::Yes => true, | 154 | 1.77k | IsNormalized::No => false, | 155 | 5.67k | IsNormalized::Maybe => s.chars().eq(s.chars().stream_safe().nfc()), | 156 | | } | 157 | 16.5k | } |
Unexecuted instantiation: unicode_normalization::quick_check::is_nfc_stream_safe |
158 | | |
159 | | /// Authoritatively check if a string is Stream-Safe NFD. |
160 | | #[inline] |
161 | 16.5k | pub fn is_nfd_stream_safe(s: &str) -> bool { |
162 | 16.5k | match is_nfd_stream_safe_quick(s.chars()) { |
163 | 13.8k | IsNormalized::Yes => true, |
164 | 2.70k | IsNormalized::No => false, |
165 | 0 | IsNormalized::Maybe => s.chars().eq(s.chars().stream_safe().nfd()), |
166 | | } |
167 | 16.5k | } unicode_normalization::quick_check::is_nfd_stream_safe Line | Count | Source | 161 | 16.5k | pub fn is_nfd_stream_safe(s: &str) -> bool { | 162 | 16.5k | match is_nfd_stream_safe_quick(s.chars()) { | 163 | 13.8k | IsNormalized::Yes => true, | 164 | 2.70k | IsNormalized::No => false, | 165 | 0 | IsNormalized::Maybe => s.chars().eq(s.chars().stream_safe().nfd()), | 166 | | } | 167 | 16.5k | } |
Unexecuted instantiation: unicode_normalization::quick_check::is_nfd_stream_safe |
168 | | |
169 | | #[cfg(test)] |
170 | | mod tests { |
171 | | use super::{is_nfc_stream_safe_quick, is_nfd_stream_safe_quick, IsNormalized}; |
172 | | |
173 | | #[test] |
174 | | fn test_stream_safe_nfd() { |
175 | | let okay = "Da\u{031b}\u{0316}\u{0317}\u{0318}\u{0319}\u{031c}\u{031d}\u{0300}\u{0301}\u{0302}\u{0303}\u{0304}\u{0305}\u{0306}\u{0307}\u{0308}\u{0309}\u{030a}\u{030b}\u{030c}\u{030d}\u{030e}\u{030f}\u{0310}\u{0311}\u{0312}\u{0313}\u{0314}\u{0315}\u{031a}ngerzone"; |
176 | | assert_eq!(is_nfd_stream_safe_quick(okay.chars()), IsNormalized::Yes); |
177 | | |
178 | | let too_much = "Da\u{031b}\u{0316}\u{0317}\u{0318}\u{0319}\u{031c}\u{031d}\u{031e}\u{0300}\u{0301}\u{0302}\u{0303}\u{0304}\u{0305}\u{0306}\u{0307}\u{0308}\u{0309}\u{030a}\u{030b}\u{030c}\u{030d}\u{030e}\u{030f}\u{0310}\u{0311}\u{0312}\u{0313}\u{0314}\u{0315}\u{031a}ngerzone"; |
179 | | assert_eq!(is_nfd_stream_safe_quick(too_much.chars()), IsNormalized::No); |
180 | | } |
181 | | |
182 | | #[test] |
183 | | fn test_stream_safe_nfc() { |
184 | | let okay = "ok\u{e0}\u{031b}\u{0316}\u{0317}\u{0318}\u{0319}\u{031c}\u{031d}\u{0301}\u{0302}\u{0303}\u{0304}\u{0305}\u{0306}\u{0307}\u{0308}\u{0309}\u{030a}\u{030b}\u{030c}\u{030d}\u{030e}\u{030f}\u{0310}\u{0311}\u{0312}\u{0313}\u{0314}\u{0315}\u{031a}y"; |
185 | | assert_eq!(is_nfc_stream_safe_quick(okay.chars()), IsNormalized::Maybe); |
186 | | |
187 | | let too_much = "not ok\u{e0}\u{031b}\u{0316}\u{0317}\u{0318}\u{0319}\u{031c}\u{031d}\u{031e}\u{0301}\u{0302}\u{0303}\u{0304}\u{0305}\u{0306}\u{0307}\u{0308}\u{0309}\u{030a}\u{030b}\u{030c}\u{030d}\u{030e}\u{030f}\u{0310}\u{0311}\u{0312}\u{0313}\u{0314}\u{0315}\u{031a}y"; |
188 | | assert_eq!(is_nfc_stream_safe_quick(too_much.chars()), IsNormalized::No); |
189 | | } |
190 | | } |