Coverage Report

Created: 2026-03-19 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/icu_properties-1.5.1/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::provider::bidi_data::{
6
    CheckedBidiPairedBracketType, MirroredPairedBracketData, MirroredPairedBracketDataTryFromError,
7
};
8
use crate::script::ScriptWithExt;
9
use crate::{
10
    BidiClass, CanonicalCombiningClass, EastAsianWidth, GeneralCategory, GeneralCategoryGroup,
11
    GraphemeClusterBreak, HangulSyllableType, IndicSyllabicCategory, JoiningType, LineBreak,
12
    Script, SentenceBreak, WordBreak,
13
};
14
use core::convert::TryInto;
15
use core::num::TryFromIntError;
16
use zerovec::ule::{AsULE, RawBytesULE};
17
18
use icu_collections::codepointtrie::TrieValue;
19
20
use core::convert::TryFrom;
21
22
impl TrieValue for CanonicalCombiningClass {
23
    type TryFromU32Error = TryFromIntError;
24
25
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
26
0
        u8::try_from(i).map(Self)
27
0
    }
28
29
0
    fn to_u32(self) -> u32 {
30
0
        u32::from(self.0)
31
0
    }
32
}
33
34
impl TrieValue for BidiClass {
35
    type TryFromU32Error = TryFromIntError;
36
37
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
38
0
        u8::try_from(i).map(Self)
39
0
    }
40
41
0
    fn to_u32(self) -> u32 {
42
0
        u32::from(self.0)
43
0
    }
44
}
45
46
impl TrieValue for GeneralCategory {
47
    type TryFromU32Error = &'static str;
48
49
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
50
        // If the u32 is out of range, fall back to u8::MAX, which is out of range of the GeneralCategory enum.
51
0
        GeneralCategory::new_from_u8(i.try_into().unwrap_or(u8::MAX))
52
0
            .ok_or("Cannot parse GeneralCategory from integer")
53
0
    }
54
55
0
    fn to_u32(self) -> u32 {
56
0
        u32::from(self as u8)
57
0
    }
58
}
59
60
impl TrieValue for Script {
61
    type TryFromU32Error = TryFromIntError;
62
63
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
64
0
        u16::try_from(i).map(Script)
65
0
    }
66
67
0
    fn to_u32(self) -> u32 {
68
0
        u32::from(self.0)
69
0
    }
70
}
71
72
impl TrieValue for HangulSyllableType {
73
    type TryFromU32Error = TryFromIntError;
74
75
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
76
0
        u8::try_from(i).map(Self)
77
0
    }
78
79
0
    fn to_u32(self) -> u32 {
80
0
        u32::from(self.0)
81
0
    }
82
}
83
84
impl TrieValue for ScriptWithExt {
85
    type TryFromU32Error = TryFromIntError;
86
87
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
88
0
        u16::try_from(i).map(Self)
89
0
    }
90
91
0
    fn to_u32(self) -> u32 {
92
0
        u32::from(self.0)
93
0
    }
94
}
95
96
impl TrieValue for EastAsianWidth {
97
    type TryFromU32Error = TryFromIntError;
98
99
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
100
0
        u8::try_from(i).map(Self)
101
0
    }
102
103
0
    fn to_u32(self) -> u32 {
104
0
        u32::from(self.0)
105
0
    }
106
}
107
108
impl TrieValue for LineBreak {
109
    type TryFromU32Error = TryFromIntError;
110
111
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
112
0
        u8::try_from(i).map(Self)
113
0
    }
114
115
0
    fn to_u32(self) -> u32 {
116
0
        u32::from(self.0)
117
0
    }
118
}
119
120
impl TrieValue for GraphemeClusterBreak {
121
    type TryFromU32Error = TryFromIntError;
122
123
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
124
0
        u8::try_from(i).map(Self)
125
0
    }
126
127
0
    fn to_u32(self) -> u32 {
128
0
        u32::from(self.0)
129
0
    }
130
}
131
132
impl TrieValue for WordBreak {
133
    type TryFromU32Error = TryFromIntError;
134
135
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
136
0
        u8::try_from(i).map(Self)
137
0
    }
138
139
0
    fn to_u32(self) -> u32 {
140
0
        u32::from(self.0)
141
0
    }
142
}
143
144
impl TrieValue for SentenceBreak {
145
    type TryFromU32Error = TryFromIntError;
146
147
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
148
0
        u8::try_from(i).map(Self)
149
0
    }
150
151
0
    fn to_u32(self) -> u32 {
152
0
        u32::from(self.0)
153
0
    }
154
}
155
156
impl TrieValue for CheckedBidiPairedBracketType {
157
    type TryFromU32Error = TryFromIntError;
158
159
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
160
0
        Ok(match i {
161
0
            1 => CheckedBidiPairedBracketType::Open,
162
0
            2 => CheckedBidiPairedBracketType::Close,
163
0
            _ => CheckedBidiPairedBracketType::None,
164
        })
165
0
    }
166
}
167
168
impl TrieValue for IndicSyllabicCategory {
169
    type TryFromU32Error = TryFromIntError;
170
171
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
172
0
        u8::try_from(i).map(Self)
173
0
    }
174
175
0
    fn to_u32(self) -> u32 {
176
0
        u32::from(self.0)
177
0
    }
178
}
179
180
// GCG is not used inside tries, but it is used in the name lookup type, and we want
181
// to squeeze it into a u16 for storage. Its named mask values are specced so we can
182
// do this in code.
183
//
184
// This is done by:
185
// - Single-value masks are translated to their corresponding GeneralCategory values
186
// - we know all of the multi-value masks and we give them special values
187
// - Anything else goes to 0xFF00, though this code path shouldn't be hit unless working with malformed icuexportdata
188
//
189
// In the reverse direction, unknown values go to the empty mask, but this codepath should not be hit except
190
// with malformed ICU4X generated data.
191
impl AsULE for GeneralCategoryGroup {
192
    type ULE = RawBytesULE<2>;
193
0
    fn to_unaligned(self) -> Self::ULE {
194
0
        let value = gcg_to_packed_u16(self);
195
0
        value.to_unaligned()
196
0
    }
197
0
    fn from_unaligned(ule: Self::ULE) -> Self {
198
0
        let value = ule.as_unsigned_int();
199
0
        packed_u16_to_gcg(value)
200
0
    }
201
}
202
203
0
fn packed_u16_to_gcg(value: u16) -> GeneralCategoryGroup {
204
0
    match value {
205
0
        0xFFFF => GeneralCategoryGroup::CasedLetter,
206
0
        0xFFFE => GeneralCategoryGroup::Letter,
207
0
        0xFFFD => GeneralCategoryGroup::Mark,
208
0
        0xFFFC => GeneralCategoryGroup::Number,
209
0
        0xFFFB => GeneralCategoryGroup::Separator,
210
0
        0xFFFA => GeneralCategoryGroup::Other,
211
0
        0xFFF9 => GeneralCategoryGroup::Punctuation,
212
0
        0xFFF8 => GeneralCategoryGroup::Symbol,
213
0
        v if v < 32 => GeneralCategory::new_from_u8(v as u8)
214
0
            .map(|gc| gc.into())
215
0
            .unwrap_or(GeneralCategoryGroup(0)),
216
        // unknown values produce an empty mask
217
0
        _ => GeneralCategoryGroup(0),
218
    }
219
0
}
220
221
0
fn gcg_to_packed_u16(gcg: GeneralCategoryGroup) -> u16 {
222
    // if it's a single property, translate to that property
223
0
    if gcg.0.count_ones() == 1 {
224
        // inverse operation of a bitshift
225
0
        gcg.0.trailing_zeros() as u16
226
    } else {
227
0
        match gcg {
228
0
            GeneralCategoryGroup::CasedLetter => 0xFFFF,
229
0
            GeneralCategoryGroup::Letter => 0xFFFE,
230
0
            GeneralCategoryGroup::Mark => 0xFFFD,
231
0
            GeneralCategoryGroup::Number => 0xFFFC,
232
0
            GeneralCategoryGroup::Separator => 0xFFFB,
233
0
            GeneralCategoryGroup::Other => 0xFFFA,
234
0
            GeneralCategoryGroup::Punctuation => 0xFFF9,
235
0
            GeneralCategoryGroup::Symbol => 0xFFF8,
236
0
            _ => 0xFF00, // random sentinel value
237
        }
238
    }
239
0
}
240
241
impl TrieValue for GeneralCategoryGroup {
242
    type TryFromU32Error = TryFromIntError;
243
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
244
        // Even though we're dealing with u32s here, TrieValue is about converting
245
        // trie storage types to the actual type. This type will always be a packed u16
246
        // in our case since the names map upcasts from u16
247
0
        u16::try_from(i).map(packed_u16_to_gcg)
248
0
    }
249
250
0
    fn to_u32(self) -> u32 {
251
0
        u32::from(gcg_to_packed_u16(self))
252
0
    }
253
}
254
255
impl TrieValue for MirroredPairedBracketData {
256
    type TryFromU32Error = MirroredPairedBracketDataTryFromError;
257
258
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
259
0
        Self::try_from(i)
260
0
    }
261
}
262
263
impl TrieValue for JoiningType {
264
    type TryFromU32Error = TryFromIntError;
265
266
0
    fn try_from_u32(i: u32) -> Result<Self, Self::TryFromU32Error> {
267
0
        u8::try_from(i).map(Self)
268
0
    }
269
270
0
    fn to_u32(self) -> u32 {
271
0
        u32::from(self.0)
272
0
    }
273
}