1
use unicode_canonical_combining_class::get_canonical_combining_class;
2

            
3
/// An enumeration of the Unicode
4
/// [Canonical_Combining_Class values](http://www.unicode.org/reports/tr44/#Canonical_Combining_Class_Values),
5
/// with the following modifications:
6
///
7
/// * Remove: `CCC84`, `CCC91`, `CCC103`.
8
/// * Add: `CCC3`, `CCC4`, `CCC5`.
9
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
10
pub enum ModifiedCombiningClass {
11
    NotReordered = 0,
12
    Overlay = 1,
13
    CCC3 = 3,
14
    CCC4 = 4,
15
    CCC5 = 5,
16
    HanReading = 6,
17
    Nukta = 7,
18
    KanaVoicing = 8,
19
    Virama = 9,
20
    CCC10 = 10,
21
    CCC11 = 11,
22
    CCC12 = 12,
23
    CCC13 = 13,
24
    CCC14 = 14,
25
    CCC15 = 15,
26
    CCC16 = 16,
27
    CCC17 = 17,
28
    CCC18 = 18,
29
    CCC19 = 19,
30
    CCC20 = 20,
31
    CCC21 = 21,
32
    CCC22 = 22,
33
    CCC23 = 23,
34
    CCC24 = 24,
35
    CCC25 = 25,
36
    CCC26 = 26,
37
    CCC27 = 27,
38
    CCC28 = 28,
39
    CCC29 = 29,
40
    CCC30 = 30,
41
    CCC31 = 31,
42
    CCC32 = 32,
43
    CCC33 = 33,
44
    CCC34 = 34,
45
    CCC35 = 35,
46
    CCC36 = 36,
47
    CCC107 = 107,
48
    CCC118 = 118,
49
    CCC122 = 122,
50
    CCC129 = 129,
51
    CCC130 = 130,
52
    CCC132 = 132,
53
    AttachedBelow = 202,
54
    AttachedAbove = 214,
55
    AttachedAboveRight = 216,
56
    BelowLeft = 218,
57
    Below = 220,
58
    BelowRight = 222,
59
    Left = 224,
60
    Right = 226,
61
    AboveLeft = 228,
62
    Above = 230,
63
    AboveRight = 232,
64
    DoubleBelow = 233,
65
    DoubleAbove = 234,
66
    IotaSubscript = 240,
67
}
68

            
69
const X: ModifiedCombiningClass = ModifiedCombiningClass::NotReordered;
70
use ModifiedCombiningClass::*;
71
const MODIFIED_COMBINING_CLASS: &[ModifiedCombiningClass; 256] = &[
72
    NotReordered, // NotReordered
73
    Overlay,      // Overlay
74
    X,            // CCC2
75
    X,            // CCC3
76
    X,            // CCC4
77
    X,            // CCC5
78
    HanReading,   // HanReading
79
    Nukta,        // Nukta
80
    KanaVoicing,  // KanaVoicing
81
    Virama,       // Virama
82
    // Hebrew
83
    // Reordered in accordance with the SBL Hebrew Font User Manual:
84
    // https://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf.
85
    CCC22, // CCC10
86
    CCC15, // CCC11
87
    CCC16, // CCC12
88
    CCC17, // CCC13
89
    CCC23, // CCC14
90
    CCC18, // CCC15
91
    CCC19, // CCC16
92
    CCC20, // CCC17
93
    CCC21, // CCC18
94
    CCC14, // CCC19
95
    CCC24, // CCC20
96
    CCC12, // CCC21
97
    CCC25, // CCC22
98
    CCC13, // CCC23
99
    CCC10, // CCC24
100
    CCC11, // CCC25
101
    CCC26, // CCC26
102
    // Arabic
103
    CCC27, // CCC27
104
    CCC28, // CCC28
105
    CCC29, // CCC29
106
    CCC30, // CCC30
107
    CCC31, // CCC31
108
    CCC32, // CCC32
109
    CCC33, // CCC33
110
    CCC34, // CCC34
111
    CCC35, // CCC35
112
    // Syriac
113
    CCC36, // CCC36
114
    X,     // CCC37
115
    X,     // CCC38
116
    X,     // CCC39
117
    X,     // CCC40
118
    X,     // CCC41
119
    X,     // CCC42
120
    X,     // CCC43
121
    X,     // CCC44
122
    X,     // CCC45
123
    X,     // CCC46
124
    X,     // CCC47
125
    X,     // CCC48
126
    X,     // CCC49
127
    X,     // CCC50
128
    X,     // CCC51
129
    X,     // CCC52
130
    X,     // CCC53
131
    X,     // CCC54
132
    X,     // CCC55
133
    X,     // CCC56
134
    X,     // CCC57
135
    X,     // CCC58
136
    X,     // CCC59
137
    X,     // CCC60
138
    X,     // CCC61
139
    X,     // CCC62
140
    X,     // CCC63
141
    X,     // CCC64
142
    X,     // CCC65
143
    X,     // CCC66
144
    X,     // CCC67
145
    X,     // CCC68
146
    X,     // CCC69
147
    X,     // CCC70
148
    X,     // CCC71
149
    X,     // CCC72
150
    X,     // CCC73
151
    X,     // CCC74
152
    X,     // CCC75
153
    X,     // CCC76
154
    X,     // CCC77
155
    X,     // CCC78
156
    X,     // CCC79
157
    X,     // CCC80
158
    X,     // CCC81
159
    X,     // CCC82
160
    X,     // CCC83
161
    // Telugu
162
    // Map `CCC84` and `CCC91` to the otherwise unassigned `CCC4` and `CCC5` values. If
163
    // left as-is, the Telugu length marks U+0C55 and U+0C56 have the undesirable effect
164
    // of being reordered after a Halant.
165
    //
166
    // Test case: `"\u{0C15}\u{0C4D}\u{0C56}"` should not produce a dotted circle.
167
    CCC4, // CCC84
168
    X,    // CCC85
169
    X,    // CCC86
170
    X,    // CCC87
171
    X,    // CCC88
172
    X,    // CCC89
173
    X,    // CCC90
174
    CCC5, // CCC91
175
    X,    // CCC92
176
    X,    // CCC93
177
    X,    // CCC94
178
    X,    // CCC95
179
    X,    // CCC96
180
    X,    // CCC97
181
    X,    // CCC98
182
    X,    // CCC99
183
    X,    // CCC100
184
    X,    // CCC101
185
    X,    // CCC102
186
    // Thai
187
    // Map `CCC103` to the otherwise unassigned `CCC3` value. If left as-is, the Thai marks
188
    // U+0E38 and U+0E39 have the undesirable effect of being reordered after a Phinthu.
189
    CCC3,   // CCC103
190
    X,      // CCC104
191
    X,      // CCC105
192
    X,      // CCC106
193
    CCC107, // CCC107
194
    X,      // CCC108
195
    X,      // CCC109
196
    X,      // CCC110
197
    X,      // CCC111
198
    X,      // CCC112
199
    X,      // CCC113
200
    X,      // CCC114
201
    X,      // CCC115
202
    X,      // CCC116
203
    X,      // CCC117
204
    // Lao
205
    CCC118, // CCC118
206
    X,      // CCC119
207
    X,      // CCC120
208
    X,      // CCC121
209
    CCC122, // CCC122
210
    X,      // CCC123
211
    X,      // CCC124
212
    X,      // CCC125
213
    X,      // CCC126
214
    X,      // CCC127
215
    X,      // CCC128
216
    // Tibetan
217
    CCC129,             // CCC129
218
    CCC130,             // CCC130
219
    X,                  // CCC131
220
    CCC132,             // CCC132
221
    X,                  // CCC133
222
    X,                  // CCC134
223
    X,                  // CCC135
224
    X,                  // CCC136
225
    X,                  // CCC137
226
    X,                  // CCC138
227
    X,                  // CCC139
228
    X,                  // CCC140
229
    X,                  // CCC141
230
    X,                  // CCC142
231
    X,                  // CCC143
232
    X,                  // CCC144
233
    X,                  // CCC145
234
    X,                  // CCC146
235
    X,                  // CCC147
236
    X,                  // CCC148
237
    X,                  // CCC149
238
    X,                  // CCC150
239
    X,                  // CCC151
240
    X,                  // CCC152
241
    X,                  // CCC153
242
    X,                  // CCC154
243
    X,                  // CCC155
244
    X,                  // CCC156
245
    X,                  // CCC157
246
    X,                  // CCC158
247
    X,                  // CCC159
248
    X,                  // CCC160
249
    X,                  // CCC161
250
    X,                  // CCC162
251
    X,                  // CCC163
252
    X,                  // CCC164
253
    X,                  // CCC165
254
    X,                  // CCC166
255
    X,                  // CCC167
256
    X,                  // CCC168
257
    X,                  // CCC169
258
    X,                  // CCC170
259
    X,                  // CCC171
260
    X,                  // CCC172
261
    X,                  // CCC173
262
    X,                  // CCC174
263
    X,                  // CCC175
264
    X,                  // CCC176
265
    X,                  // CCC177
266
    X,                  // CCC178
267
    X,                  // CCC179
268
    X,                  // CCC180
269
    X,                  // CCC181
270
    X,                  // CCC182
271
    X,                  // CCC183
272
    X,                  // CCC184
273
    X,                  // CCC185
274
    X,                  // CCC186
275
    X,                  // CCC187
276
    X,                  // CCC188
277
    X,                  // CCC189
278
    X,                  // CCC190
279
    X,                  // CCC191
280
    X,                  // CCC192
281
    X,                  // CCC193
282
    X,                  // CCC194
283
    X,                  // CCC195
284
    X,                  // CCC196
285
    X,                  // CCC197
286
    X,                  // CCC198
287
    X,                  // CCC199
288
    X,                  // CCC200
289
    X,                  // CCC201
290
    AttachedBelow,      // AttachedBelow
291
    X,                  // CCC203
292
    X,                  // CCC204
293
    X,                  // CCC205
294
    X,                  // CCC206
295
    X,                  // CCC207
296
    X,                  // CCC208
297
    X,                  // CCC209
298
    X,                  // CCC210
299
    X,                  // CCC211
300
    X,                  // CCC212
301
    X,                  // CCC213
302
    AttachedAbove,      // AttachedAbove
303
    X,                  // CCC215
304
    AttachedAboveRight, // AttachedAboveRight
305
    X,                  // CCC217
306
    BelowLeft,          // BelowLeft
307
    X,                  // CCC219
308
    Below,              // Below
309
    X,                  // CCC221
310
    BelowRight,         // BelowRight
311
    X,                  // CCC223
312
    Left,               // Left
313
    X,                  // CCC225
314
    Right,              // Right
315
    X,                  // CCC227
316
    AboveLeft,          // AboveLeft
317
    X,                  // CCC229
318
    Above,              // Above
319
    X,                  // CCC231
320
    AboveRight,         // AboveRight
321
    DoubleBelow,        // DoubleBelow
322
    DoubleAbove,        // DoubleAbove
323
    X,                  // CCC235
324
    X,                  // CCC236
325
    X,                  // CCC237
326
    X,                  // CCC238
327
    X,                  // CCC239
328
    IotaSubscript,      // IotaSubscript
329
    X,                  // CCC241
330
    X,                  // CCC242
331
    X,                  // CCC243
332
    X,                  // CCC244
333
    X,                  // CCC245
334
    X,                  // CCC246
335
    X,                  // CCC247
336
    X,                  // CCC248
337
    X,                  // CCC249
338
    X,                  // CCC250
339
    X,                  // CCC251
340
    X,                  // CCC252
341
    X,                  // CCC253
342
    X,                  // CCC254
343
    X,                  // CCC255
344
];
345

            
346
/// Returns the modified combining class value of a `char`. Retrieves the _canonical_ combining
347
/// class value, then maps it to its corresponding _modified_ value.
348
pub fn modified_combining_class(c: char) -> ModifiedCombiningClass {
349
    if c <= '\u{02FF}' {
350
        // Fast path, primarily for Latin. None of the code points in:
351
        //     U+0000..U+007F | Basic Latin
352
        //     U+0080..U+00FF | Latin-1 Supplement
353
        //     U+0100..U+017F | Latin Extended-A
354
        //     U+0180..U+024F | Latin Extended-B
355
        //     U+0250..U+02AF | IPA Extensions
356
        //     U+02B0..U+02FF | Spacing Modifier Letters
357
        // are reordering marks.
358
        ModifiedCombiningClass::NotReordered
359
    } else {
360
        MODIFIED_COMBINING_CLASS[get_canonical_combining_class(c) as usize]
361
    }
362
}
363

            
364
/// Sorts sub-slices of non-starter `char`s (i.e. `char`s with non-zero combining class values) by
365
/// their modified combining class values. This sort is stable.
366
pub fn sort_by_modified_combining_class(cs: &mut [char]) {
367
    for css in
368
        cs.split_mut(|&c| modified_combining_class(c) == ModifiedCombiningClass::NotReordered)
369
    {
370
        css.sort_by_key(|&c| modified_combining_class(c));
371
    }
372
}