• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zbraniecki / icu4x / 9457158389

10 Jun 2024 11:45PM UTC coverage: 75.174% (+0.05%) from 75.121%
9457158389

push

github

web-flow
Add constructing TinyAsciiStr from utf16 (#5025)

Introduces TinyAsciiStr constructors from utf16 and converges on the
consensus from #4931.

---------

Co-authored-by: Robert Bastian <4706271+robertbastian@users.noreply.github.com>

65 of 82 new or added lines in 14 files covered. (79.27%)

3441 existing lines in 141 files now uncovered.

52850 of 70304 relevant lines covered (75.17%)

563298.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.03
/components/properties/src/script.rs
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
//! Data and APIs for supporting both Script and Script_Extensions property
6
//! values in an efficient structure.
7

8
use crate::props::Script;
9
use crate::props::ScriptULE;
10
use crate::provider::*;
11

12
use core::iter::FromIterator;
13
use core::ops::RangeInclusive;
14
use icu_collections::codepointinvlist::CodePointInversionList;
15
use icu_provider::prelude::*;
16
use zerovec::{ule::AsULE, ZeroSlice};
17

18
/// The number of bits at the low-end of a `ScriptWithExt` value used for
19
/// storing the `Script` value (or `extensions` index).
20
const SCRIPT_VAL_LENGTH: u16 = 10;
21

22
/// The bit mask necessary to retrieve the `Script` value (or `extensions` index)
23
/// from a `ScriptWithExt` value.
24
const SCRIPT_X_SCRIPT_VAL: u16 = (1 << SCRIPT_VAL_LENGTH) - 1;
25

26
/// An internal-use only pseudo-property that represents the values stored in
27
/// the trie of the special data structure [`ScriptWithExtensionsPropertyV1`].
28
///
29
/// Note: The will assume a 12-bit layout. The 2 higher order bits in positions
30
/// 11..10 will indicate how to deduce the Script value and Script_Extensions,
31
/// and the lower 10 bits 9..0 indicate either the Script value or the index
32
/// into the `extensions` structure.
33
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
701,356✔
UNCOV
34
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
×
35
#[cfg_attr(feature = "datagen", derive(databake::Bake))]
×
36
#[cfg_attr(feature = "datagen", databake(path = icu_properties::script))]
37
#[repr(transparent)]
38
#[doc(hidden)]
39
// `ScriptWithExt` not intended as public-facing but for `ScriptWithExtensionsPropertyV1` constructor
40
#[allow(clippy::exhaustive_structs)] // this type is stable
41
pub struct ScriptWithExt(pub u16);
464,698✔
42

43
#[allow(missing_docs)] // These constants don't need individual documentation.
44
#[allow(non_upper_case_globals)]
45
#[doc(hidden)] // `ScriptWithExt` not intended as public-facing but for `ScriptWithExtensionsPropertyV1` constructor
46
impl ScriptWithExt {
47
    pub const Unknown: ScriptWithExt = ScriptWithExt(0);
48
}
49

50
impl AsULE for ScriptWithExt {
51
    type ULE = ScriptULE;
52

53
    #[inline]
54
    fn to_unaligned(self) -> Self::ULE {
50,150✔
55
        Script(self.0).to_unaligned()
50,150✔
56
    }
50,150✔
57

58
    #[inline]
59
    fn from_unaligned(unaligned: Self::ULE) -> Self {
295,445✔
60
        ScriptWithExt(Script::from_unaligned(unaligned).0)
295,445✔
61
    }
295,445✔
62
}
63

64
#[doc(hidden)] // `ScriptWithExt` not intended as public-facing but for `ScriptWithExtensionsPropertyV1` constructor
65
impl ScriptWithExt {
66
    /// Returns whether the [`ScriptWithExt`] value has Script_Extensions and
67
    /// also indicates a Script value of [`Script::Common`].
68
    ///
69
    /// # Examples
70
    ///
71
    /// ```
72
    /// use icu::properties::script::ScriptWithExt;
73
    ///
74
    /// assert!(ScriptWithExt(0x04FF).is_common());
75
    /// assert!(ScriptWithExt(0x0400).is_common());
76
    ///
77
    /// assert!(!ScriptWithExt(0x08FF).is_common());
78
    /// assert!(!ScriptWithExt(0x0800).is_common());
79
    ///
80
    /// assert!(!ScriptWithExt(0x0CFF).is_common());
81
    /// assert!(!ScriptWithExt(0x0C00).is_common());
82
    ///
83
    /// assert!(!ScriptWithExt(0xFF).is_common());
84
    /// assert!(!ScriptWithExt(0x0).is_common());
85
    /// ```
86
    pub fn is_common(&self) -> bool {
1,600✔
87
        self.0 >> SCRIPT_VAL_LENGTH == 1
1,600✔
88
    }
1,600✔
89

90
    /// Returns whether the [`ScriptWithExt`] value has Script_Extensions and
91
    /// also indicates a Script value of [`Script::Inherited`].
92
    ///
93
    /// # Examples
94
    ///
95
    /// ```
96
    /// use icu::properties::script::ScriptWithExt;
97
    ///
98
    /// assert!(!ScriptWithExt(0x04FF).is_inherited());
99
    /// assert!(!ScriptWithExt(0x0400).is_inherited());
100
    ///
101
    /// assert!(ScriptWithExt(0x08FF).is_inherited());
102
    /// assert!(ScriptWithExt(0x0800).is_inherited());
103
    ///
104
    /// assert!(!ScriptWithExt(0x0CFF).is_inherited());
105
    /// assert!(!ScriptWithExt(0x0C00).is_inherited());
106
    ///
107
    /// assert!(!ScriptWithExt(0xFF).is_inherited());
108
    /// assert!(!ScriptWithExt(0x0).is_inherited());
109
    /// ```
110
    pub fn is_inherited(&self) -> bool {
545✔
111
        self.0 >> SCRIPT_VAL_LENGTH == 2
545✔
112
    }
545✔
113

114
    /// Returns whether the [`ScriptWithExt`] value has Script_Extensions and
115
    /// also indicates that the Script value is neither [`Script::Common`] nor
116
    /// [`Script::Inherited`].
117
    ///
118
    /// # Examples
119
    ///
120
    /// ```
121
    /// use icu::properties::script::ScriptWithExt;
122
    ///
123
    /// assert!(!ScriptWithExt(0x04FF).is_other());
124
    /// assert!(!ScriptWithExt(0x0400).is_other());
125
    ///
126
    /// assert!(!ScriptWithExt(0x08FF).is_other());
127
    /// assert!(!ScriptWithExt(0x0800).is_other());
128
    ///
129
    /// assert!(ScriptWithExt(0x0CFF).is_other());
130
    /// assert!(ScriptWithExt(0x0C00).is_other());
131
    ///
132
    /// assert!(!ScriptWithExt(0xFF).is_other());
133
    /// assert!(!ScriptWithExt(0x0).is_other());
134
    /// ```
135
    pub fn is_other(&self) -> bool {
2,004✔
136
        self.0 >> SCRIPT_VAL_LENGTH == 3
2,004✔
137
    }
2,004✔
138

139
    /// Returns whether the [`ScriptWithExt`] value has Script_Extensions.
140
    ///
141
    /// # Examples
142
    ///
143
    /// ```
144
    /// use icu::properties::script::ScriptWithExt;
145
    ///
146
    /// assert!(ScriptWithExt(0x04FF).has_extensions());
147
    /// assert!(ScriptWithExt(0x0400).has_extensions());
148
    ///
149
    /// assert!(ScriptWithExt(0x08FF).has_extensions());
150
    /// assert!(ScriptWithExt(0x0800).has_extensions());
151
    ///
152
    /// assert!(ScriptWithExt(0x0CFF).has_extensions());
153
    /// assert!(ScriptWithExt(0x0C00).has_extensions());
154
    ///
155
    /// assert!(!ScriptWithExt(0xFF).has_extensions());
156
    /// assert!(!ScriptWithExt(0x0).has_extensions());
157
    /// ```
158
    pub fn has_extensions(&self) -> bool {
26,467✔
159
        let high_order_bits = self.0 >> SCRIPT_VAL_LENGTH;
26,467✔
160
        high_order_bits > 0
26,467✔
161
    }
26,467✔
162
}
163

164
impl From<ScriptWithExt> for u32 {
UNCOV
165
    fn from(swe: ScriptWithExt) -> Self {
×
166
        swe.0 as u32
×
167
    }
×
168
}
169

170
impl From<ScriptWithExt> for Script {
171
    fn from(swe: ScriptWithExt) -> Self {
24,510✔
172
        Script(swe.0)
24,510✔
173
    }
24,510✔
174
}
175

176
/// A struct that wraps a [`Script`] array, such as in the return value for
177
/// [`get_script_extensions_val()`](ScriptWithExtensionsBorrowed::get_script_extensions_val).
UNCOV
178
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
×
179
pub struct ScriptExtensionsSet<'a> {
UNCOV
180
    values: &'a ZeroSlice<Script>,
×
181
}
182

183
impl<'a> ScriptExtensionsSet<'a> {
184
    /// Returns whether this set contains the given script.
185
    ///
186
    /// # Example
187
    ///
188
    /// ```
189
    /// use icu::properties::{script, Script};
190
    /// let swe = script::script_with_extensions();
191
    ///
192
    /// assert!(swe
193
    ///     .get_script_extensions_val(0x11303) // GRANTHA SIGN VISARGA
194
    ///     .contains(&Script::Grantha));
195
    /// ```
196
    pub fn contains(&self, x: &Script) -> bool {
3✔
197
        ZeroSlice::binary_search(self.values, x).is_ok()
3✔
198
    }
3✔
199

200
    /// Gets an iterator over the elements.
201
    ///
202
    /// # Example
203
    ///
204
    /// ```
205
    /// use icu::properties::{script, Script};
206
    /// let swe = script::script_with_extensions();
207
    ///
208
    /// assert_eq!(
209
    ///     swe.get_script_extensions_val('௫' as u32) // U+0BEB TAMIL DIGIT FIVE
210
    ///         .iter()
211
    ///         .collect::<Vec<Script>>(),
212
    ///     vec![Script::Tamil, Script::Grantha]
213
    /// );
214
    /// ```
215
    pub fn iter(&self) -> impl DoubleEndedIterator<Item = Script> + 'a {
17✔
216
        ZeroSlice::iter(self.values)
17✔
217
    }
17✔
218

219
    /// For accessing this set as an array instead of an iterator
220
    #[doc(hidden)] // used by FFI code
UNCOV
221
    pub fn array_len(&self) -> usize {
×
UNCOV
222
        self.values.len()
×
223
    }
×
224
    /// For accessing this set as an array instead of an iterator
225
    #[doc(hidden)] // used by FFI code
UNCOV
226
    pub fn array_get(&self, index: usize) -> Option<Script> {
×
UNCOV
227
        self.values.get(index)
×
UNCOV
228
    }
×
229
}
230

231
/// A wrapper around script extensions data. Can be obtained via [`load_script_with_extensions_unstable()`] and
232
/// related getters.
233
///
234
/// Most useful methods are on [`ScriptWithExtensionsBorrowed`] obtained by calling [`ScriptWithExtensions::as_borrowed()`]
UNCOV
235
#[derive(Debug)]
×
236
pub struct ScriptWithExtensions {
UNCOV
237
    data: DataPayload<ScriptWithExtensionsPropertyV1Marker>,
×
238
}
239

240
/// A borrowed wrapper around script extension data, returned by
241
/// [`ScriptWithExtensions::as_borrowed()`]. More efficient to query.
UNCOV
242
#[derive(Clone, Copy, Debug)]
×
243
pub struct ScriptWithExtensionsBorrowed<'a> {
UNCOV
244
    data: &'a ScriptWithExtensionsPropertyV1<'a>,
×
245
}
246

247
impl ScriptWithExtensions {
248
    /// Construct a borrowed version of this type that can be queried.
249
    ///
250
    /// This avoids a potential small underlying cost per API call (ex: `contains()`) by consolidating it
251
    /// up front.
252
    #[inline]
253
    pub fn as_borrowed(&self) -> ScriptWithExtensionsBorrowed<'_> {
8✔
254
        ScriptWithExtensionsBorrowed {
8✔
255
            data: self.data.get(),
8✔
256
        }
257
    }
8✔
258

259
    /// Construct a new one from loaded data
260
    ///
261
    /// Typically it is preferable to use getters like [`load_script_with_extensions_unstable()`] instead
262
    pub fn from_data(data: DataPayload<ScriptWithExtensionsPropertyV1Marker>) -> Self {
16✔
263
        Self { data }
16✔
264
    }
16✔
265
}
266

267
impl<'a> ScriptWithExtensionsBorrowed<'a> {
268
    /// Returns the `Script` property value for this code point.
269
    ///
270
    /// # Examples
271
    ///
272
    /// ```
273
    /// use icu::properties::{script, Script};
274
    ///
275
    /// let swe = script::script_with_extensions();
276
    ///
277
    /// // U+0640 ARABIC TATWEEL
278
    /// assert_eq!(swe.get_script_val(0x0640), Script::Common); // main Script value
279
    /// assert_ne!(swe.get_script_val(0x0640), Script::Arabic);
280
    /// assert_ne!(swe.get_script_val(0x0640), Script::Syriac);
281
    /// assert_ne!(swe.get_script_val(0x0640), Script::Thaana);
282
    ///
283
    /// // U+0650 ARABIC KASRA
284
    /// assert_eq!(swe.get_script_val(0x0650), Script::Inherited); // main Script value
285
    /// assert_ne!(swe.get_script_val(0x0650), Script::Arabic);
286
    /// assert_ne!(swe.get_script_val(0x0650), Script::Syriac);
287
    /// assert_ne!(swe.get_script_val(0x0650), Script::Thaana);
288
    ///
289
    /// // U+0660 ARABIC-INDIC DIGIT ZERO
290
    /// assert_ne!(swe.get_script_val(0x0660), Script::Common);
291
    /// assert_eq!(swe.get_script_val(0x0660), Script::Arabic); // main Script value
292
    /// assert_ne!(swe.get_script_val(0x0660), Script::Syriac);
293
    /// assert_ne!(swe.get_script_val(0x0660), Script::Thaana);
294
    ///
295
    /// // U+FDF2 ARABIC LIGATURE ALLAH ISOLATED FORM
296
    /// assert_ne!(swe.get_script_val(0xFDF2), Script::Common);
297
    /// assert_eq!(swe.get_script_val(0xFDF2), Script::Arabic); // main Script value
298
    /// assert_ne!(swe.get_script_val(0xFDF2), Script::Syriac);
299
    /// assert_ne!(swe.get_script_val(0xFDF2), Script::Thaana);
300
    /// ```
301
    pub fn get_script_val(self, code_point: u32) -> Script {
38✔
302
        let sc_with_ext = self.data.trie.get32(code_point);
38✔
303

304
        if sc_with_ext.is_other() {
38✔
305
            let ext_idx = sc_with_ext.0 & SCRIPT_X_SCRIPT_VAL;
12✔
306
            let scx_val = self.data.extensions.get(ext_idx as usize);
12✔
307
            let scx_first_sc = scx_val.and_then(|scx| scx.get(0));
24✔
308

309
            let default_sc_val = Script::Unknown;
38✔
310

311
            scx_first_sc.unwrap_or(default_sc_val)
12✔
312
        } else if sc_with_ext.is_common() {
26✔
313
            Script::Common
6✔
314
        } else if sc_with_ext.is_inherited() {
20✔
315
            Script::Inherited
5✔
316
        } else {
317
            let script_val = sc_with_ext.0;
15✔
318
            Script(script_val)
15✔
319
        }
320
    }
38✔
321
    // Returns the Script_Extensions value for a code_point when the trie value
322
    // is already known.
323
    // This private helper method exists to prevent code duplication in callers like
324
    // `get_script_extensions_val`, `get_script_extensions_set`, and `has_script`.
325
    fn get_scx_val_using_trie_val(
1,958✔
326
        self,
327
        sc_with_ext_ule: &'a <ScriptWithExt as AsULE>::ULE,
328
    ) -> &'a ZeroSlice<Script> {
329
        let sc_with_ext = ScriptWithExt::from_unaligned(*sc_with_ext_ule);
1,958✔
330
        if sc_with_ext.is_other() {
1,958✔
331
            let ext_idx = sc_with_ext.0 & SCRIPT_X_SCRIPT_VAL;
392✔
332
            let ext_subarray = self.data.extensions.get(ext_idx as usize);
392✔
333
            // In the OTHER case, where the 2 higher-order bits of the
334
            // `ScriptWithExt` value in the trie doesn't indicate the Script value,
335
            // the Script value is copied/inserted into the first position of the
336
            // `extensions` array. So we must remove it to return the actual scx array val.
337
            let scx_slice = ext_subarray
392✔
338
                .and_then(|zslice| zslice.as_ule_slice().get(1..))
392✔
339
                .unwrap_or_default();
340
            ZeroSlice::from_ule_slice(scx_slice)
392✔
341
        } else if sc_with_ext.is_common() || sc_with_ext.is_inherited() {
1,566✔
342
            let ext_idx = sc_with_ext.0 & SCRIPT_X_SCRIPT_VAL;
1,556✔
343
            let scx_val = self.data.extensions.get(ext_idx as usize);
1,556✔
344
            scx_val.unwrap_or_default()
1,556✔
345
        } else {
346
            // Note: `Script` and `ScriptWithExt` are both represented as the same
347
            // u16 value when the `ScriptWithExt` has no higher-order bits set.
348
            let script_ule_slice = core::slice::from_ref(sc_with_ext_ule);
10✔
349
            ZeroSlice::from_ule_slice(script_ule_slice)
10✔
350
        }
351
    }
1,958✔
352
    /// Return the `Script_Extensions` property value for this code point.
353
    ///
354
    /// If `code_point` has Script_Extensions, then return the Script codes in
355
    /// the Script_Extensions. In this case, the Script property value
356
    /// (normally Common or Inherited) is not included in the [`ScriptExtensionsSet`].
357
    ///
358
    /// If c does not have Script_Extensions, then the one Script code is put
359
    /// into the [`ScriptExtensionsSet`] and also returned.
360
    ///
361
    /// If c is not a valid code point, then return an empty [`ScriptExtensionsSet`].
362
    ///
363
    /// # Examples
364
    ///
365
    /// ```
366
    /// use icu::properties::{script, Script};
367
    ///
368
    /// let swe = script::script_with_extensions();
369
    ///
370
    /// assert_eq!(
371
    ///     swe.get_script_extensions_val('𐓐' as u32) // U+104D0 OSAGE CAPITAL LETTER KHA
372
    ///         .iter()
373
    ///         .collect::<Vec<Script>>(),
374
    ///     vec![Script::Osage]
375
    /// );
376
    /// assert_eq!(
377
    ///     swe.get_script_extensions_val('🥳' as u32) // U+1F973 FACE WITH PARTY HORN AND PARTY HAT
378
    ///         .iter()
379
    ///         .collect::<Vec<Script>>(),
380
    ///     vec![Script::Common]
381
    /// );
382
    /// assert_eq!(
383
    ///     swe.get_script_extensions_val(0x200D) // ZERO WIDTH JOINER
384
    ///         .iter()
385
    ///         .collect::<Vec<Script>>(),
386
    ///     vec![Script::Inherited]
387
    /// );
388
    /// assert_eq!(
389
    ///     swe.get_script_extensions_val('௫' as u32) // U+0BEB TAMIL DIGIT FIVE
390
    ///         .iter()
391
    ///         .collect::<Vec<Script>>(),
392
    ///     vec![Script::Tamil, Script::Grantha]
393
    /// );
394
    /// ```
395
    pub fn get_script_extensions_val(self, code_point: u32) -> ScriptExtensionsSet<'a> {
20✔
396
        let sc_with_ext_ule = self.data.trie.get32_ule(code_point);
20✔
397

398
        ScriptExtensionsSet {
20✔
399
            values: match sc_with_ext_ule {
40✔
400
                Some(ule_ref) => self.get_scx_val_using_trie_val(ule_ref),
20✔
UNCOV
401
                None => ZeroSlice::from_ule_slice(&[]),
×
402
            },
403
        }
404
    }
20✔
405

406
    /// Returns whether `script` is contained in the Script_Extensions
407
    /// property value if the code_point has Script_Extensions, otherwise
408
    /// if the code point does not have Script_Extensions then returns
409
    /// whether the Script property value matches.
410
    ///
411
    /// Some characters are commonly used in multiple scripts. For more information,
412
    /// see UAX #24: <http://www.unicode.org/reports/tr24/>.
413
    ///
414
    /// # Examples
415
    ///
416
    /// ```
417
    /// use icu::properties::{script, Script};
418
    ///
419
    /// let swe = script::script_with_extensions();
420
    ///
421
    /// // U+0650 ARABIC KASRA
422
    /// assert!(!swe.has_script(0x0650, Script::Inherited)); // main Script value
423
    /// assert!(swe.has_script(0x0650, Script::Arabic));
424
    /// assert!(swe.has_script(0x0650, Script::Syriac));
425
    /// assert!(!swe.has_script(0x0650, Script::Thaana));
426
    ///
427
    /// // U+0660 ARABIC-INDIC DIGIT ZERO
428
    /// assert!(!swe.has_script(0x0660, Script::Common)); // main Script value
429
    /// assert!(swe.has_script(0x0660, Script::Arabic));
430
    /// assert!(!swe.has_script(0x0660, Script::Syriac));
431
    /// assert!(swe.has_script(0x0660, Script::Thaana));
432
    ///
433
    /// // U+FDF2 ARABIC LIGATURE ALLAH ISOLATED FORM
434
    /// assert!(!swe.has_script(0xFDF2, Script::Common));
435
    /// assert!(swe.has_script(0xFDF2, Script::Arabic)); // main Script value
436
    /// assert!(!swe.has_script(0xFDF2, Script::Syriac));
437
    /// assert!(swe.has_script(0xFDF2, Script::Thaana));
438
    /// ```
439
    pub fn has_script(self, code_point: u32, script: Script) -> bool {
59✔
440
        let sc_with_ext_ule = if let Some(scwe_ule) = self.data.trie.get32_ule(code_point) {
59✔
441
            scwe_ule
442
        } else {
UNCOV
443
            return false;
×
444
        };
445
        let sc_with_ext = <ScriptWithExt as AsULE>::from_unaligned(*sc_with_ext_ule);
59✔
446

447
        if !sc_with_ext.has_extensions() {
59✔
448
            let script_val = sc_with_ext.0;
11✔
449
            script == Script(script_val)
11✔
450
        } else {
451
            let scx_val = self.get_scx_val_using_trie_val(sc_with_ext_ule);
48✔
452
            let script_find = scx_val.iter().find(|&sc| sc == script);
175✔
453
            script_find.is_some()
48✔
454
        }
455
    }
59✔
456

457
    /// Returns all of the matching `CodePointMapRange`s for the given [`Script`]
458
    /// in which `has_script` will return true for all of the contained code points.
459
    ///
460
    /// # Examples
461
    ///
462
    /// ```
463
    /// use icu::properties::{script, Script};
464
    ///
465
    /// let swe = script::script_with_extensions();
466
    ///
467
    /// let syriac_script_extensions_ranges = swe.get_script_extensions_ranges(Script::Syriac);
468
    ///
469
    /// let exp_ranges = vec![
470
    ///     0x060C..=0x060C, // ARABIC COMMA
471
    ///     0x061B..=0x061C, // ARABIC SEMICOLON, ARABIC LETTER MARK
472
    ///     0x061F..=0x061F, // ARABIC QUESTION MARK
473
    ///     0x0640..=0x0640, // ARABIC TATWEEL
474
    ///     0x064B..=0x0655, // ARABIC FATHATAN..ARABIC HAMZA BELOW
475
    ///     0x0670..=0x0670, // ARABIC LETTER SUPERSCRIPT ALEF
476
    ///     0x0700..=0x070D, // Syriac block begins at U+0700
477
    ///     0x070F..=0x074A, // Syriac block
478
    ///     0x074D..=0x074F, // Syriac block ends at U+074F
479
    ///     0x0860..=0x086A, // Syriac Supplement block is U+0860..=U+086F
480
    ///     0x1DF8..=0x1DF8, // U+1DF8 COMBINING DOT ABOVE LEFT
481
    ///     0x1DFA..=0x1DFA, // U+1DFA COMBINING DOT BELOW LEFT
482
    /// ];
483
    /// let mut exp_ranges_iter = exp_ranges.iter();
484
    ///
485
    /// for act_range in syriac_script_extensions_ranges {
486
    ///     let exp_range = exp_ranges_iter
487
    ///         .next()
488
    ///         .expect("There are too many ranges returned by get_script_extensions_ranges()");
489
    ///     assert_eq!(act_range.start(), exp_range.start());
490
    ///     assert_eq!(act_range.end(), exp_range.end());
491
    /// }
492
    /// assert!(
493
    ///     exp_ranges_iter.next().is_none(),
494
    ///     "There are too few ranges returned by get_script_extensions_ranges()"
495
    /// );
496
    /// ```
497
    pub fn get_script_extensions_ranges(
15✔
498
        self,
499
        script: Script,
500
    ) -> impl Iterator<Item = RangeInclusive<u32>> + 'a {
501
        self.data
30✔
502
            .trie
503
            .iter_ranges_mapped(move |value| {
26,415✔
504
                let sc_with_ext = ScriptWithExt(value.0);
26,400✔
505
                if sc_with_ext.has_extensions() {
26,400✔
506
                    self.get_scx_val_using_trie_val(&sc_with_ext.to_unaligned())
3,780✔
507
                        .iter()
508
                        .any(|sc| sc == script)
7,786✔
509
                } else {
510
                    script == sc_with_ext.into()
24,510✔
511
                }
512
            })
26,400✔
513
            .filter(|v| v.value)
924✔
514
            .map(|v| v.range)
455✔
515
    }
15✔
516

517
    /// Returns a [`CodePointInversionList`] for the given [`Script`] which represents all
518
    /// code points for which `has_script` will return true.
519
    ///
520
    /// # Examples
521
    ///
522
    /// ```
523
    /// use icu::properties::{script, Script};
524
    ///
525
    /// let swe = script::script_with_extensions();
526
    ///
527
    /// let syriac = swe.get_script_extensions_set(Script::Syriac);
528
    ///
529
    /// assert!(!syriac.contains32(0x061E)); // ARABIC TRIPLE DOT PUNCTUATION MARK
530
    /// assert!(syriac.contains32(0x061F)); // ARABIC QUESTION MARK
531
    /// assert!(!syriac.contains32(0x0620)); // ARABIC LETTER KASHMIRI YEH
532
    ///
533
    /// assert!(syriac.contains32(0x0700)); // SYRIAC END OF PARAGRAPH
534
    /// assert!(syriac.contains32(0x074A)); // SYRIAC BARREKH
535
    /// assert!(!syriac.contains32(0x074B)); // unassigned
536
    /// assert!(syriac.contains32(0x074F)); // SYRIAC LETTER SOGDIAN FE
537
    /// assert!(!syriac.contains32(0x0750)); // ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW
538
    ///
539
    /// assert!(syriac.contains32(0x1DF8)); // COMBINING DOT ABOVE LEFT
540
    /// assert!(!syriac.contains32(0x1DF9)); // COMBINING WIDE INVERTED BRIDGE BELOW
541
    /// assert!(syriac.contains32(0x1DFA)); // COMBINING DOT BELOW LEFT
542
    /// assert!(!syriac.contains32(0x1DFB)); // COMBINING DELETION MARK
543
    /// ```
544
    pub fn get_script_extensions_set(self, script: Script) -> CodePointInversionList<'a> {
14✔
545
        CodePointInversionList::from_iter(self.get_script_extensions_ranges(script))
14✔
546
    }
14✔
547
}
548

549
impl ScriptWithExtensionsBorrowed<'static> {
550
    /// Cheaply converts a [`ScriptWithExtensionsBorrowed<'static>`] into a [`ScriptWithExtensions`].
551
    ///
552
    /// Note: Due to branching and indirection, using [`ScriptWithExtensions`] might inhibit some
553
    /// compile-time optimizations that are possible with [`ScriptWithExtensionsBorrowed`].
UNCOV
554
    pub const fn static_to_owned(self) -> ScriptWithExtensions {
×
UNCOV
555
        ScriptWithExtensions {
×
UNCOV
556
            data: DataPayload::from_static_ref(self.data),
×
557
        }
558
    }
×
559
}
560

561
/// Returns a [`ScriptWithExtensionsBorrowed`] struct that represents the data for the Script
562
/// and Script_Extensions properties.
563
///
564
/// ✨ *Enabled with the `compiled_data` Cargo feature.*
565
///
566
/// [📚 Help choosing a constructor](icu_provider::constructors)
567
///
568
/// # Examples
569
///
570
/// ```
571
/// use icu::properties::{script, Script};
572
/// let swe = script::script_with_extensions();
573
///
574
/// // get the `Script` property value
575
/// assert_eq!(swe.get_script_val(0x0640), Script::Common); // U+0640 ARABIC TATWEEL
576
/// assert_eq!(swe.get_script_val(0x0650), Script::Inherited); // U+0650 ARABIC KASRA
577
/// assert_eq!(swe.get_script_val(0x0660), Script::Arabic); // // U+0660 ARABIC-INDIC DIGIT ZERO
578
/// assert_eq!(swe.get_script_val(0xFDF2), Script::Arabic); // U+FDF2 ARABIC LIGATURE ALLAH ISOLATED FORM
579
///
580
/// // get the `Script_Extensions` property value
581
/// assert_eq!(
582
///     swe.get_script_extensions_val(0x0640) // U+0640 ARABIC TATWEEL
583
///         .iter().collect::<Vec<Script>>(),
584
///     vec![Script::Arabic, Script::Syriac, Script::Mandaic, Script::Manichaean,
585
///          Script::PsalterPahlavi, Script::Adlam, Script::HanifiRohingya, Script::Sogdian,
586
///          Script::OldUyghur]
587
/// );
588
/// assert_eq!(
589
///     swe.get_script_extensions_val('🥳' as u32) // U+1F973 FACE WITH PARTY HORN AND PARTY HAT
590
///         .iter().collect::<Vec<Script>>(),
591
///     vec![Script::Common]
592
/// );
593
/// assert_eq!(
594
///     swe.get_script_extensions_val(0x200D) // ZERO WIDTH JOINER
595
///         .iter().collect::<Vec<Script>>(),
596
///     vec![Script::Inherited]
597
/// );
598
/// assert_eq!(
599
///     swe.get_script_extensions_val('௫' as u32) // U+0BEB TAMIL DIGIT FIVE
600
///         .iter().collect::<Vec<Script>>(),
601
///     vec![Script::Tamil, Script::Grantha]
602
/// );
603
///
604
/// // check containment of a `Script` value in the `Script_Extensions` value
605
/// // U+0650 ARABIC KASRA
606
/// assert!(!swe.has_script(0x0650, Script::Inherited)); // main Script value
607
/// assert!(swe.has_script(0x0650, Script::Arabic));
608
/// assert!(swe.has_script(0x0650, Script::Syriac));
609
/// assert!(!swe.has_script(0x0650, Script::Thaana));
610
///
611
/// // get a `CodePointInversionList` for when `Script` value is contained in `Script_Extensions` value
612
/// let syriac = swe.get_script_extensions_set(Script::Syriac);
613
/// assert!(syriac.contains32(0x0650)); // ARABIC KASRA
614
/// assert!(!syriac.contains32(0x0660)); // ARABIC-INDIC DIGIT ZERO
615
/// assert!(!syriac.contains32(0xFDF2)); // ARABIC LIGATURE ALLAH ISOLATED FORM
616
/// assert!(syriac.contains32(0x0700)); // SYRIAC END OF PARAGRAPH
617
/// assert!(syriac.contains32(0x074A)); // SYRIAC BARREKH
618
/// ```
619
#[cfg(feature = "compiled_data")]
620
pub const fn script_with_extensions() -> ScriptWithExtensionsBorrowed<'static> {
9✔
621
    ScriptWithExtensionsBorrowed {
9✔
622
        data: crate::provider::Baked::SINGLETON_PROPS_SCX_V1,
623
    }
624
}
9✔
625

626
icu_provider::gen_any_buffer_data_constructors!(
627
    locale: skip,
628
    options: skip,
629
    result: Result<ScriptWithExtensions, DataError>,
630
    #[cfg(skip)]
631
    functions: [
632
        script_with_extensions,
633
        load_script_with_extensions_with_any_provider,
634
        load_script_with_extensions_with_buffer_provider,
635
        load_script_with_extensions_unstable,
636
    ]
637
);
638

639
#[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, script_with_extensions)]
640
pub fn load_script_with_extensions_unstable(
4✔
641
    provider: &(impl DataProvider<ScriptWithExtensionsPropertyV1Marker> + ?Sized),
642
) -> Result<ScriptWithExtensions, DataError> {
643
    provider
4✔
644
        .load(Default::default())
4✔
645
        .and_then(DataResponse::take_payload)
646
        .map(ScriptWithExtensions::from_data)
647
}
4✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc