Coverage Report

Created: 2026-10-28 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/icu_properties-2.4.0/src/trievalue.rs
Line
Count
Source
1
// This file is part of ICU4X. For terms of use, please see the file
2
// called LICENSE at the top level of the ICU4X source tree
3
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5
use crate::bidi::BidiMirroringGlyph;
6
use crate::props::{
7
    BidiClass, Block, CanonicalCombiningClass, EastAsianWidth, GeneralCategory,
8
    GeneralCategoryGroup, GraphemeClusterBreak, HangulSyllableType, IndicConjunctBreak,
9
    IndicSyllabicCategory, JoiningGroup, JoiningType, LineBreak, NumericType, Script,
10
    SentenceBreak, VerticalOrientation, WordBreak,
11
};
12
use crate::script::ScriptWithExt;
13
use core::convert::TryInto;
14
use core::num::TryFromIntError;
15
use zerovec::ule::{AsULE, RawBytesULE};
16
17
use icu_collections::codepointtrie::TrieValue;
18
19
use core::convert::TryFrom;
20
21
impl TrieValue for CanonicalCombiningClass {
22
    type TryFromU32Error = TryFromIntError;
23
24
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
25
0
        u8::try_from(i).map(Self)
26
0
    }
27
28
0
    fn to_u32(self) -> u32 {
29
0
        u32::from(self.0)
30
0
    }
31
}
32
33
impl TrieValue for NumericType {
34
    type TryFromU32Error = TryFromIntError;
35
36
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
37
0
        u8::try_from(i).map(Self)
38
0
    }
39
40
0
    fn to_u32(self) -> u32 {
41
0
        u32::from(self.0)
42
0
    }
43
}
44
45
impl TrieValue for BidiClass {
46
    type TryFromU32Error = TryFromIntError;
47
48
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
49
0
        u8::try_from(i).map(Self)
50
0
    }
51
52
0
    fn to_u32(self) -> u32 {
53
0
        u32::from(self.0)
54
0
    }
55
}
56
57
impl TrieValue for Block {
58
    type TryFromU32Error = TryFromIntError;
59
60
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
61
0
        u16::try_from(i).map(Self)
62
0
    }
63
64
0
    fn to_u32(self) -> u32 {
65
0
        u32::from(self.0)
66
0
    }
67
}
68
69
impl TrieValue for GeneralCategory {
70
    type TryFromU32Error = &'static str;
71
72
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
73
        // If the u32 is out of range, fall back to u8::MAX, which is out of range of the GeneralCategory enum.
74
0
        GeneralCategory::new_from_u8(i.try_into().unwrap_or(u8::MAX))
75
0
            .ok_or("Cannot parse GeneralCategory from integer")
76
0
    }
77
78
0
    fn to_u32(self) -> u32 {
79
0
        u32::from(self as u8)
80
0
    }
81
}
82
83
impl TrieValue for Script {
84
    type TryFromU32Error = TryFromIntError;
85
86
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
87
0
        u16::try_from(i).map(Script)
88
0
    }
89
90
0
    fn to_u32(self) -> u32 {
91
0
        u32::from(self.0)
92
0
    }
93
}
94
95
impl TrieValue for HangulSyllableType {
96
    type TryFromU32Error = TryFromIntError;
97
98
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
99
0
        u8::try_from(i).map(Self)
100
0
    }
101
102
0
    fn to_u32(self) -> u32 {
103
0
        u32::from(self.0)
104
0
    }
105
}
106
107
impl TrieValue for ScriptWithExt {
108
    type TryFromU32Error = TryFromIntError;
109
110
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
111
0
        u16::try_from(i).map(Self)
112
0
    }
113
114
0
    fn to_u32(self) -> u32 {
115
0
        u32::from(self.0)
116
0
    }
117
}
118
119
impl TrieValue for EastAsianWidth {
120
    type TryFromU32Error = TryFromIntError;
121
122
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
123
0
        u8::try_from(i).map(Self)
124
0
    }
125
126
0
    fn to_u32(self) -> u32 {
127
0
        u32::from(self.0)
128
0
    }
129
}
130
131
impl TrieValue for LineBreak {
132
    type TryFromU32Error = TryFromIntError;
133
134
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
135
0
        u8::try_from(i).map(Self)
136
0
    }
137
138
0
    fn to_u32(self) -> u32 {
139
0
        u32::from(self.0)
140
0
    }
141
}
142
143
impl TrieValue for GraphemeClusterBreak {
144
    type TryFromU32Error = TryFromIntError;
145
146
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
147
0
        u8::try_from(i).map(Self)
148
0
    }
149
150
0
    fn to_u32(self) -> u32 {
151
0
        u32::from(self.0)
152
0
    }
153
}
154
155
impl TrieValue for WordBreak {
156
    type TryFromU32Error = TryFromIntError;
157
158
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
159
0
        u8::try_from(i).map(Self)
160
0
    }
161
162
0
    fn to_u32(self) -> u32 {
163
0
        u32::from(self.0)
164
0
    }
165
}
166
167
impl TrieValue for SentenceBreak {
168
    type TryFromU32Error = TryFromIntError;
169
170
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
171
0
        u8::try_from(i).map(Self)
172
0
    }
173
174
0
    fn to_u32(self) -> u32 {
175
0
        u32::from(self.0)
176
0
    }
177
}
178
179
impl TrieValue for IndicConjunctBreak {
180
    type TryFromU32Error = TryFromIntError;
181
182
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
183
0
        u8::try_from(i).map(Self)
184
0
    }
185
186
0
    fn to_u32(self) -> u32 {
187
0
        u32::from(self.0)
188
0
    }
189
}
190
191
impl TrieValue for IndicSyllabicCategory {
192
    type TryFromU32Error = TryFromIntError;
193
194
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
195
0
        u8::try_from(i).map(Self)
196
0
    }
197
198
0
    fn to_u32(self) -> u32 {
199
0
        u32::from(self.0)
200
0
    }
201
}
202
203
impl TrieValue for VerticalOrientation {
204
    type TryFromU32Error = TryFromIntError;
205
206
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
207
0
        u8::try_from(i).map(Self)
208
0
    }
209
210
0
    fn to_u32(self) -> u32 {
211
0
        u32::from(self.0)
212
0
    }
213
}
214
215
// GCG is not used inside tries, but it is used in the name lookup type, and we want
216
// to squeeze it into a u16 for storage. Its named mask values are specced so we can
217
// do this in code.
218
//
219
// This is done by:
220
// - Single-value masks are translated to their corresponding GeneralCategory values
221
// - we know all of the multi-value masks and we give them special values
222
// - Anything else goes to 0xFF00, though this code path shouldn't be hit unless working with malformed icuexportdata
223
//
224
// In the reverse direction, unknown values go to the empty mask, but this codepath should not be hit except
225
// with malformed ICU4X generated data.
226
impl AsULE for GeneralCategoryGroup {
227
    type ULE = RawBytesULE<2>;
228
0
    fn to_unaligned(self) -> Self::ULE {
229
0
        let value = gcg_to_packed_u16(self);
230
0
        value.to_unaligned()
231
0
    }
232
0
    fn from_unaligned(ule: Self::ULE) -> Self {
233
0
        let value = ule.as_unsigned_int();
234
0
        packed_u16_to_gcg(value)
235
0
    }
236
}
237
238
0
fn packed_u16_to_gcg(value: u16) -> GeneralCategoryGroup {
239
0
    match value {
240
0
        0xFFFF => GeneralCategoryGroup::CasedLetter,
241
0
        0xFFFE => GeneralCategoryGroup::Letter,
242
0
        0xFFFD => GeneralCategoryGroup::Mark,
243
0
        0xFFFC => GeneralCategoryGroup::Number,
244
0
        0xFFFB => GeneralCategoryGroup::Separator,
245
0
        0xFFFA => GeneralCategoryGroup::Other,
246
0
        0xFFF9 => GeneralCategoryGroup::Punctuation,
247
0
        0xFFF8 => GeneralCategoryGroup::Symbol,
248
0
        v if v < 32 => GeneralCategory::new_from_u8(v as u8)
249
0
            .map(|gc| gc.into())
250
0
            .unwrap_or(GeneralCategoryGroup(0)),
251
        // unknown values produce an empty mask
252
0
        _ => GeneralCategoryGroup(0),
253
    }
254
0
}
255
256
0
fn gcg_to_packed_u16(gcg: GeneralCategoryGroup) -> u16 {
257
    // if it's a single property, translate to that property
258
0
    if gcg.0.is_power_of_two() {
259
        // inverse operation of a bitshift
260
0
        gcg.0.trailing_zeros() as u16
261
    } else {
262
0
        match gcg {
263
0
            GeneralCategoryGroup::CasedLetter => 0xFFFF,
264
0
            GeneralCategoryGroup::Letter => 0xFFFE,
265
0
            GeneralCategoryGroup::Mark => 0xFFFD,
266
0
            GeneralCategoryGroup::Number => 0xFFFC,
267
0
            GeneralCategoryGroup::Separator => 0xFFFB,
268
0
            GeneralCategoryGroup::Other => 0xFFFA,
269
0
            GeneralCategoryGroup::Punctuation => 0xFFF9,
270
0
            GeneralCategoryGroup::Symbol => 0xFFF8,
271
0
            _ => 0xFF00, // random sentinel value
272
        }
273
    }
274
0
}
275
276
impl TrieValue for GeneralCategoryGroup {
277
    type TryFromU32Error = TryFromIntError;
278
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
279
        // Even though we're dealing with u32s here, TrieValue is about converting
280
        // trie storage types to the actual type. This type will always be a packed u16
281
        // in our case since the names map upcasts from u16
282
0
        u16::try_from(i).map(packed_u16_to_gcg)
283
0
    }
284
285
0
    fn to_u32(self) -> u32 {
286
0
        u32::from(gcg_to_packed_u16(self))
287
0
    }
288
}
289
290
impl TrieValue for BidiMirroringGlyph {
291
    type TryFromU32Error = u32;
292
293
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
294
0
        let code_point = i & 0x1FFFFF;
295
0
        let mirroring_glyph = if code_point == 0 {
296
0
            None
297
        } else {
298
0
            Some(char::try_from_u32(code_point).map_err(|_| i)?)
299
        };
300
0
        let mirrored = ((i >> 21) & 0x1) == 1;
301
0
        let paired_bracket_type = {
302
0
            let value = ((i >> 22) & 0x3) as u8;
303
0
            match value {
304
0
                0 => crate::bidi::BidiPairedBracketType::None,
305
0
                1 => crate::bidi::BidiPairedBracketType::Open,
306
0
                2 => crate::bidi::BidiPairedBracketType::Close,
307
0
                _ => return Err(i),
308
            }
309
        };
310
0
        Ok(Self {
311
0
            mirrored,
312
0
            mirroring_glyph,
313
0
            paired_bracket_type,
314
0
        })
315
0
    }
316
317
0
    fn to_u32(self) -> u32 {
318
0
        self.mirroring_glyph.unwrap_or_default() as u32
319
0
            | ((self.mirrored as u32) << 21)
320
0
            | (match self.paired_bracket_type {
321
0
                crate::bidi::BidiPairedBracketType::None => 0,
322
0
                crate::bidi::BidiPairedBracketType::Open => 1,
323
0
                crate::bidi::BidiPairedBracketType::Close => 2,
324
            } << 22)
325
0
    }
326
}
327
328
impl TrieValue for JoiningType {
329
    type TryFromU32Error = TryFromIntError;
330
331
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
332
0
        u8::try_from(i).map(Self)
333
0
    }
334
335
0
    fn to_u32(self) -> u32 {
336
0
        u32::from(self.0)
337
0
    }
338
}
339
340
impl TrieValue for JoiningGroup {
341
    type TryFromU32Error = TryFromIntError;
342
343
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
344
0
        u8::try_from(i).map(Self)
345
0
    }
346
0
    fn to_u32(self) -> u32 {
347
0
        u32::from(self.0)
348
0
    }
349
}