Coverage Report

Created: 2025-07-12 07:16

/rust/registry/src/index.crates.io-6f17d22bba15001f/icu_properties-1.5.1/src/script.rs
Line
Count
Source (jump to first uncovered line)
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::error::PropertiesError;
9
use crate::props::Script;
10
use crate::props::ScriptULE;
11
use crate::provider::*;
12
13
use core::iter::FromIterator;
14
use core::ops::RangeInclusive;
15
use icu_collections::codepointinvlist::CodePointInversionList;
16
use icu_provider::prelude::*;
17
use zerovec::{ule::AsULE, ZeroSlice};
18
19
/// The number of bits at the low-end of a `ScriptWithExt` value used for
20
/// storing the `Script` value (or `extensions` index).
21
const SCRIPT_VAL_LENGTH: u16 = 10;
22
23
/// The bit mask necessary to retrieve the `Script` value (or `extensions` index)
24
/// from a `ScriptWithExt` value.
25
const SCRIPT_X_SCRIPT_VAL: u16 = (1 << SCRIPT_VAL_LENGTH) - 1;
26
27
/// An internal-use only pseudo-property that represents the values stored in
28
/// the trie of the special data structure [`ScriptWithExtensionsPropertyV1`].
29
///
30
/// Note: The will assume a 12-bit layout. The 2 higher order bits in positions
31
/// 11..10 will indicate how to deduce the Script value and Script_Extensions,
32
/// and the lower 10 bits 9..0 indicate either the Script value or the index
33
/// into the `extensions` structure.
34
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
35
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36
#[cfg_attr(feature = "datagen", derive(databake::Bake))]
37
#[cfg_attr(feature = "datagen", databake(path = icu_properties::script))]
38
#[repr(transparent)]
39
#[doc(hidden)]
40
// `ScriptWithExt` not intended as public-facing but for `ScriptWithExtensionsPropertyV1` constructor
41
#[allow(clippy::exhaustive_structs)] // this type is stable
42
pub struct ScriptWithExt(pub u16);
43
44
#[allow(missing_docs)] // These constants don't need individual documentation.
45
#[allow(non_upper_case_globals)]
46
#[doc(hidden)] // `ScriptWithExt` not intended as public-facing but for `ScriptWithExtensionsPropertyV1` constructor
47
impl ScriptWithExt {
48
    pub const Unknown: ScriptWithExt = ScriptWithExt(0);
49
}
50
51
impl AsULE for ScriptWithExt {
52
    type ULE = ScriptULE;
53
54
    #[inline]
55
0
    fn to_unaligned(self) -> Self::ULE {
56
0
        Script(self.0).to_unaligned()
57
0
    }
58
59
    #[inline]
60
0
    fn from_unaligned(unaligned: Self::ULE) -> Self {
61
0
        ScriptWithExt(Script::from_unaligned(unaligned).0)
62
0
    }
63
}
64
65
#[doc(hidden)] // `ScriptWithExt` not intended as public-facing but for `ScriptWithExtensionsPropertyV1` constructor
66
impl ScriptWithExt {
67
    /// Returns whether the [`ScriptWithExt`] value has Script_Extensions and
68
    /// also indicates a Script value of [`Script::Common`].
69
    ///
70
    /// # Examples
71
    ///
72
    /// ```
73
    /// use icu::properties::script::ScriptWithExt;
74
    ///
75
    /// assert!(ScriptWithExt(0x04FF).is_common());
76
    /// assert!(ScriptWithExt(0x0400).is_common());
77
    ///
78
    /// assert!(!ScriptWithExt(0x08FF).is_common());
79
    /// assert!(!ScriptWithExt(0x0800).is_common());
80
    ///
81
    /// assert!(!ScriptWithExt(0x0CFF).is_common());
82
    /// assert!(!ScriptWithExt(0x0C00).is_common());
83
    ///
84
    /// assert!(!ScriptWithExt(0xFF).is_common());
85
    /// assert!(!ScriptWithExt(0x0).is_common());
86
    /// ```
87
0
    pub fn is_common(&self) -> bool {
88
0
        self.0 >> SCRIPT_VAL_LENGTH == 1
89
0
    }
90
91
    /// Returns whether the [`ScriptWithExt`] value has Script_Extensions and
92
    /// also indicates a Script value of [`Script::Inherited`].
93
    ///
94
    /// # Examples
95
    ///
96
    /// ```
97
    /// use icu::properties::script::ScriptWithExt;
98
    ///
99
    /// assert!(!ScriptWithExt(0x04FF).is_inherited());
100
    /// assert!(!ScriptWithExt(0x0400).is_inherited());
101
    ///
102
    /// assert!(ScriptWithExt(0x08FF).is_inherited());
103
    /// assert!(ScriptWithExt(0x0800).is_inherited());
104
    ///
105
    /// assert!(!ScriptWithExt(0x0CFF).is_inherited());
106
    /// assert!(!ScriptWithExt(0x0C00).is_inherited());
107
    ///
108
    /// assert!(!ScriptWithExt(0xFF).is_inherited());
109
    /// assert!(!ScriptWithExt(0x0).is_inherited());
110
    /// ```
111
0
    pub fn is_inherited(&self) -> bool {
112
0
        self.0 >> SCRIPT_VAL_LENGTH == 2
113
0
    }
114
115
    /// Returns whether the [`ScriptWithExt`] value has Script_Extensions and
116
    /// also indicates that the Script value is neither [`Script::Common`] nor
117
    /// [`Script::Inherited`].
118
    ///
119
    /// # Examples
120
    ///
121
    /// ```
122
    /// use icu::properties::script::ScriptWithExt;
123
    ///
124
    /// assert!(!ScriptWithExt(0x04FF).is_other());
125
    /// assert!(!ScriptWithExt(0x0400).is_other());
126
    ///
127
    /// assert!(!ScriptWithExt(0x08FF).is_other());
128
    /// assert!(!ScriptWithExt(0x0800).is_other());
129
    ///
130
    /// assert!(ScriptWithExt(0x0CFF).is_other());
131
    /// assert!(ScriptWithExt(0x0C00).is_other());
132
    ///
133
    /// assert!(!ScriptWithExt(0xFF).is_other());
134
    /// assert!(!ScriptWithExt(0x0).is_other());
135
    /// ```
136
0
    pub fn is_other(&self) -> bool {
137
0
        self.0 >> SCRIPT_VAL_LENGTH == 3
138
0
    }
139
140
    /// Returns whether the [`ScriptWithExt`] value has Script_Extensions.
141
    ///
142
    /// # Examples
143
    ///
144
    /// ```
145
    /// use icu::properties::script::ScriptWithExt;
146
    ///
147
    /// assert!(ScriptWithExt(0x04FF).has_extensions());
148
    /// assert!(ScriptWithExt(0x0400).has_extensions());
149
    ///
150
    /// assert!(ScriptWithExt(0x08FF).has_extensions());
151
    /// assert!(ScriptWithExt(0x0800).has_extensions());
152
    ///
153
    /// assert!(ScriptWithExt(0x0CFF).has_extensions());
154
    /// assert!(ScriptWithExt(0x0C00).has_extensions());
155
    ///
156
    /// assert!(!ScriptWithExt(0xFF).has_extensions());
157
    /// assert!(!ScriptWithExt(0x0).has_extensions());
158
    /// ```
159
0
    pub fn has_extensions(&self) -> bool {
160
0
        let high_order_bits = self.0 >> SCRIPT_VAL_LENGTH;
161
0
        high_order_bits > 0
162
0
    }
163
}
164
165
impl From<ScriptWithExt> for u32 {
166
0
    fn from(swe: ScriptWithExt) -> Self {
167
0
        swe.0 as u32
168
0
    }
169
}
170
171
impl From<ScriptWithExt> for Script {
172
0
    fn from(swe: ScriptWithExt) -> Self {
173
0
        Script(swe.0)
174
0
    }
175
}
176
177
/// A struct that wraps a [`Script`] array, such as in the return value for
178
/// [`get_script_extensions_val()`](ScriptWithExtensionsBorrowed::get_script_extensions_val).
179
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
180
pub struct ScriptExtensionsSet<'a> {
181
    values: &'a ZeroSlice<Script>,
182
}
183
184
impl<'a> ScriptExtensionsSet<'a> {
185
    /// Returns whether this set contains the given script.
186
    ///
187
    /// # Example
188
    ///
189
    /// ```
190
    /// use icu::properties::{script, Script};
191
    /// let swe = script::script_with_extensions();
192
    ///
193
    /// assert!(swe
194
    ///     .get_script_extensions_val(0x11303) // GRANTHA SIGN VISARGA
195
    ///     .contains(&Script::Grantha));
196
    /// ```
197
0
    pub fn contains(&self, x: &Script) -> bool {
198
0
        ZeroSlice::binary_search(self.values, x).is_ok()
199
0
    }
200
201
    /// Gets an iterator over the elements.
202
    ///
203
    /// # Example
204
    ///
205
    /// ```
206
    /// use icu::properties::{script, Script};
207
    /// let swe = script::script_with_extensions();
208
    ///
209
    /// assert_eq!(
210
    ///     swe.get_script_extensions_val('௫' as u32) // U+0BEB TAMIL DIGIT FIVE
211
    ///         .iter()
212
    ///         .collect::<Vec<Script>>(),
213
    ///     vec![Script::Tamil, Script::Grantha]
214
    /// );
215
    /// ```
216
0
    pub fn iter(&self) -> impl DoubleEndedIterator<Item = Script> + 'a {
217
0
        ZeroSlice::iter(self.values)
218
0
    }
219
220
    /// For accessing this set as an array instead of an iterator
221
    /// only needed for the FFI bindings; shouldn't be used directly from Rust
222
    #[doc(hidden)]
223
0
    pub fn array_len(&self) -> usize {
224
0
        self.values.len()
225
0
    }
226
    /// For accessing this set as an array instead of an iterator
227
    /// only needed for the FFI bindings; shouldn't be used directly from Rust
228
    #[doc(hidden)]
229
0
    pub fn array_get(&self, index: usize) -> Option<Script> {
230
0
        self.values.get(index)
231
0
    }
232
}
233
234
/// A wrapper around script extensions data. Can be obtained via [`load_script_with_extensions_unstable()`] and
235
/// related getters.
236
///
237
/// Most useful methods are on [`ScriptWithExtensionsBorrowed`] obtained by calling [`ScriptWithExtensions::as_borrowed()`]
238
#[derive(Debug)]
239
pub struct ScriptWithExtensions {
240
    data: DataPayload<ScriptWithExtensionsPropertyV1Marker>,
241
}
242
243
/// A borrowed wrapper around script extension data, returned by
244
/// [`ScriptWithExtensions::as_borrowed()`]. More efficient to query.
245
#[derive(Clone, Copy, Debug)]
246
pub struct ScriptWithExtensionsBorrowed<'a> {
247
    data: &'a ScriptWithExtensionsPropertyV1<'a>,
248
}
249
250
impl ScriptWithExtensions {
251
    /// Construct a borrowed version of this type that can be queried.
252
    ///
253
    /// This avoids a potential small underlying cost per API call (ex: `contains()`) by consolidating it
254
    /// up front.
255
    #[inline]
256
0
    pub fn as_borrowed(&self) -> ScriptWithExtensionsBorrowed<'_> {
257
0
        ScriptWithExtensionsBorrowed {
258
0
            data: self.data.get(),
259
0
        }
260
0
    }
Unexecuted instantiation: <icu_properties::script::ScriptWithExtensions>::as_borrowed
Unexecuted instantiation: <icu_properties::script::ScriptWithExtensions>::as_borrowed
261
262
    /// Construct a new one from loaded data
263
    ///
264
    /// Typically it is preferable to use getters like [`load_script_with_extensions_unstable()`] instead
265
0
    pub fn from_data(data: DataPayload<ScriptWithExtensionsPropertyV1Marker>) -> Self {
266
0
        Self { data }
267
0
    }
268
}
269
270
impl<'a> ScriptWithExtensionsBorrowed<'a> {
271
    /// Returns the `Script` property value for this code point.
272
    ///
273
    /// # Examples
274
    ///
275
    /// ```
276
    /// use icu::properties::{script, Script};
277
    ///
278
    /// let swe = script::script_with_extensions();
279
    ///
280
    /// // U+0640 ARABIC TATWEEL
281
    /// assert_eq!(swe.get_script_val(0x0640), Script::Common); // main Script value
282
    /// assert_ne!(swe.get_script_val(0x0640), Script::Arabic);
283
    /// assert_ne!(swe.get_script_val(0x0640), Script::Syriac);
284
    /// assert_ne!(swe.get_script_val(0x0640), Script::Thaana);
285
    ///
286
    /// // U+0650 ARABIC KASRA
287
    /// assert_eq!(swe.get_script_val(0x0650), Script::Inherited); // main Script value
288
    /// assert_ne!(swe.get_script_val(0x0650), Script::Arabic);
289
    /// assert_ne!(swe.get_script_val(0x0650), Script::Syriac);
290
    /// assert_ne!(swe.get_script_val(0x0650), Script::Thaana);
291
    ///
292
    /// // U+0660 ARABIC-INDIC DIGIT ZERO
293
    /// assert_ne!(swe.get_script_val(0x0660), Script::Common);
294
    /// assert_eq!(swe.get_script_val(0x0660), Script::Arabic); // main Script value
295
    /// assert_ne!(swe.get_script_val(0x0660), Script::Syriac);
296
    /// assert_ne!(swe.get_script_val(0x0660), Script::Thaana);
297
    ///
298
    /// // U+FDF2 ARABIC LIGATURE ALLAH ISOLATED FORM
299
    /// assert_ne!(swe.get_script_val(0xFDF2), Script::Common);
300
    /// assert_eq!(swe.get_script_val(0xFDF2), Script::Arabic); // main Script value
301
    /// assert_ne!(swe.get_script_val(0xFDF2), Script::Syriac);
302
    /// assert_ne!(swe.get_script_val(0xFDF2), Script::Thaana);
303
    /// ```
304
0
    pub fn get_script_val(self, code_point: u32) -> Script {
305
0
        let sc_with_ext = self.data.trie.get32(code_point);
306
0
307
0
        if sc_with_ext.is_other() {
308
0
            let ext_idx = sc_with_ext.0 & SCRIPT_X_SCRIPT_VAL;
309
0
            let scx_val = self.data.extensions.get(ext_idx as usize);
310
0
            let scx_first_sc = scx_val.and_then(|scx| scx.get(0));
311
0
312
0
            let default_sc_val = Script::Unknown;
313
0
314
0
            scx_first_sc.unwrap_or(default_sc_val)
315
0
        } else if sc_with_ext.is_common() {
316
0
            Script::Common
317
0
        } else if sc_with_ext.is_inherited() {
318
0
            Script::Inherited
319
        } else {
320
0
            let script_val = sc_with_ext.0;
321
0
            Script(script_val)
322
        }
323
0
    }
324
    // Returns the Script_Extensions value for a code_point when the trie value
325
    // is already known.
326
    // This private helper method exists to prevent code duplication in callers like
327
    // `get_script_extensions_val`, `get_script_extensions_set`, and `has_script`.
328
0
    fn get_scx_val_using_trie_val(
329
0
        self,
330
0
        sc_with_ext_ule: &'a <ScriptWithExt as AsULE>::ULE,
331
0
    ) -> &'a ZeroSlice<Script> {
332
0
        let sc_with_ext = ScriptWithExt::from_unaligned(*sc_with_ext_ule);
333
0
        if sc_with_ext.is_other() {
334
0
            let ext_idx = sc_with_ext.0 & SCRIPT_X_SCRIPT_VAL;
335
0
            let ext_subarray = self.data.extensions.get(ext_idx as usize);
336
0
            // In the OTHER case, where the 2 higher-order bits of the
337
0
            // `ScriptWithExt` value in the trie doesn't indicate the Script value,
338
0
            // the Script value is copied/inserted into the first position of the
339
0
            // `extensions` array. So we must remove it to return the actual scx array val.
340
0
            let scx_slice = ext_subarray
341
0
                .and_then(|zslice| zslice.as_ule_slice().get(1..))
342
0
                .unwrap_or_default();
343
0
            ZeroSlice::from_ule_slice(scx_slice)
344
0
        } else if sc_with_ext.is_common() || sc_with_ext.is_inherited() {
345
0
            let ext_idx = sc_with_ext.0 & SCRIPT_X_SCRIPT_VAL;
346
0
            let scx_val = self.data.extensions.get(ext_idx as usize);
347
0
            scx_val.unwrap_or_default()
348
        } else {
349
            // Note: `Script` and `ScriptWithExt` are both represented as the same
350
            // u16 value when the `ScriptWithExt` has no higher-order bits set.
351
0
            let script_ule_slice = core::slice::from_ref(sc_with_ext_ule);
352
0
            ZeroSlice::from_ule_slice(script_ule_slice)
353
        }
354
0
    }
355
    /// Return the `Script_Extensions` property value for this code point.
356
    ///
357
    /// If `code_point` has Script_Extensions, then return the Script codes in
358
    /// the Script_Extensions. In this case, the Script property value
359
    /// (normally Common or Inherited) is not included in the [`ScriptExtensionsSet`].
360
    ///
361
    /// If c does not have Script_Extensions, then the one Script code is put
362
    /// into the [`ScriptExtensionsSet`] and also returned.
363
    ///
364
    /// If c is not a valid code point, then return an empty [`ScriptExtensionsSet`].
365
    ///
366
    /// # Examples
367
    ///
368
    /// ```
369
    /// use icu::properties::{script, Script};
370
    ///
371
    /// let swe = script::script_with_extensions();
372
    ///
373
    /// assert_eq!(
374
    ///     swe.get_script_extensions_val('𐓐' as u32) // U+104D0 OSAGE CAPITAL LETTER KHA
375
    ///         .iter()
376
    ///         .collect::<Vec<Script>>(),
377
    ///     vec![Script::Osage]
378
    /// );
379
    /// assert_eq!(
380
    ///     swe.get_script_extensions_val('🥳' as u32) // U+1F973 FACE WITH PARTY HORN AND PARTY HAT
381
    ///         .iter()
382
    ///         .collect::<Vec<Script>>(),
383
    ///     vec![Script::Common]
384
    /// );
385
    /// assert_eq!(
386
    ///     swe.get_script_extensions_val(0x200D) // ZERO WIDTH JOINER
387
    ///         .iter()
388
    ///         .collect::<Vec<Script>>(),
389
    ///     vec![Script::Inherited]
390
    /// );
391
    /// assert_eq!(
392
    ///     swe.get_script_extensions_val('௫' as u32) // U+0BEB TAMIL DIGIT FIVE
393
    ///         .iter()
394
    ///         .collect::<Vec<Script>>(),
395
    ///     vec![Script::Tamil, Script::Grantha]
396
    /// );
397
    /// ```
398
0
    pub fn get_script_extensions_val(self, code_point: u32) -> ScriptExtensionsSet<'a> {
399
0
        let sc_with_ext_ule = self.data.trie.get32_ule(code_point);
400
0
401
0
        ScriptExtensionsSet {
402
0
            values: match sc_with_ext_ule {
403
0
                Some(ule_ref) => self.get_scx_val_using_trie_val(ule_ref),
404
0
                None => ZeroSlice::from_ule_slice(&[]),
405
            },
406
        }
407
0
    }
408
409
    /// Returns whether `script` is contained in the Script_Extensions
410
    /// property value if the code_point has Script_Extensions, otherwise
411
    /// if the code point does not have Script_Extensions then returns
412
    /// whether the Script property value matches.
413
    ///
414
    /// Some characters are commonly used in multiple scripts. For more information,
415
    /// see UAX #24: <http://www.unicode.org/reports/tr24/>.
416
    ///
417
    /// # Examples
418
    ///
419
    /// ```
420
    /// use icu::properties::{script, Script};
421
    ///
422
    /// let swe = script::script_with_extensions();
423
    ///
424
    /// // U+0650 ARABIC KASRA
425
    /// assert!(!swe.has_script(0x0650, Script::Inherited)); // main Script value
426
    /// assert!(swe.has_script(0x0650, Script::Arabic));
427
    /// assert!(swe.has_script(0x0650, Script::Syriac));
428
    /// assert!(!swe.has_script(0x0650, Script::Thaana));
429
    ///
430
    /// // U+0660 ARABIC-INDIC DIGIT ZERO
431
    /// assert!(!swe.has_script(0x0660, Script::Common)); // main Script value
432
    /// assert!(swe.has_script(0x0660, Script::Arabic));
433
    /// assert!(!swe.has_script(0x0660, Script::Syriac));
434
    /// assert!(swe.has_script(0x0660, Script::Thaana));
435
    ///
436
    /// // U+FDF2 ARABIC LIGATURE ALLAH ISOLATED FORM
437
    /// assert!(!swe.has_script(0xFDF2, Script::Common));
438
    /// assert!(swe.has_script(0xFDF2, Script::Arabic)); // main Script value
439
    /// assert!(!swe.has_script(0xFDF2, Script::Syriac));
440
    /// assert!(swe.has_script(0xFDF2, Script::Thaana));
441
    /// ```
442
0
    pub fn has_script(self, code_point: u32, script: Script) -> bool {
443
0
        let sc_with_ext_ule = if let Some(scwe_ule) = self.data.trie.get32_ule(code_point) {
444
0
            scwe_ule
445
        } else {
446
0
            return false;
447
        };
448
0
        let sc_with_ext = <ScriptWithExt as AsULE>::from_unaligned(*sc_with_ext_ule);
449
0
450
0
        if !sc_with_ext.has_extensions() {
451
0
            let script_val = sc_with_ext.0;
452
0
            script == Script(script_val)
453
        } else {
454
0
            let scx_val = self.get_scx_val_using_trie_val(sc_with_ext_ule);
455
0
            let script_find = scx_val.iter().find(|&sc| sc == script);
456
0
            script_find.is_some()
457
        }
458
0
    }
459
460
    /// Returns all of the matching `CodePointMapRange`s for the given [`Script`]
461
    /// in which `has_script` will return true for all of the contained code points.
462
    ///
463
    /// # Examples
464
    ///
465
    /// ```
466
    /// use icu::properties::{script, Script};
467
    ///
468
    /// let swe = script::script_with_extensions();
469
    ///
470
    /// let syriac_script_extensions_ranges = swe.get_script_extensions_ranges(Script::Syriac);
471
    ///
472
    /// let exp_ranges = vec![
473
    ///     0x060C..=0x060C, // ARABIC COMMA
474
    ///     0x061B..=0x061C, // ARABIC SEMICOLON, ARABIC LETTER MARK
475
    ///     0x061F..=0x061F, // ARABIC QUESTION MARK
476
    ///     0x0640..=0x0640, // ARABIC TATWEEL
477
    ///     0x064B..=0x0655, // ARABIC FATHATAN..ARABIC HAMZA BELOW
478
    ///     0x0670..=0x0670, // ARABIC LETTER SUPERSCRIPT ALEF
479
    ///     0x0700..=0x070D, // Syriac block begins at U+0700
480
    ///     0x070F..=0x074A, // Syriac block
481
    ///     0x074D..=0x074F, // Syriac block ends at U+074F
482
    ///     0x0860..=0x086A, // Syriac Supplement block is U+0860..=U+086F
483
    ///     0x1DF8..=0x1DF8, // U+1DF8 COMBINING DOT ABOVE LEFT
484
    ///     0x1DFA..=0x1DFA, // U+1DFA COMBINING DOT BELOW LEFT
485
    /// ];
486
    /// let mut exp_ranges_iter = exp_ranges.iter();
487
    ///
488
    /// for act_range in syriac_script_extensions_ranges {
489
    ///     let exp_range = exp_ranges_iter
490
    ///         .next()
491
    ///         .expect("There are too many ranges returned by get_script_extensions_ranges()");
492
    ///     assert_eq!(act_range.start(), exp_range.start());
493
    ///     assert_eq!(act_range.end(), exp_range.end());
494
    /// }
495
    /// assert!(
496
    ///     exp_ranges_iter.next().is_none(),
497
    ///     "There are too few ranges returned by get_script_extensions_ranges()"
498
    /// );
499
    /// ```
500
0
    pub fn get_script_extensions_ranges(
501
0
        self,
502
0
        script: Script,
503
0
    ) -> impl Iterator<Item = RangeInclusive<u32>> + 'a {
504
0
        self.data
505
0
            .trie
506
0
            .iter_ranges_mapped(move |value| {
507
0
                let sc_with_ext = ScriptWithExt(value.0);
508
0
                if sc_with_ext.has_extensions() {
509
0
                    self.get_scx_val_using_trie_val(&sc_with_ext.to_unaligned())
510
0
                        .iter()
511
0
                        .any(|sc| sc == script)
512
                } else {
513
0
                    script == sc_with_ext.into()
514
                }
515
0
            })
516
0
            .filter(|v| v.value)
517
0
            .map(|v| v.range)
518
0
    }
519
520
    /// Returns a [`CodePointInversionList`] for the given [`Script`] which represents all
521
    /// code points for which `has_script` will return true.
522
    ///
523
    /// # Examples
524
    ///
525
    /// ```
526
    /// use icu::properties::{script, Script};
527
    ///
528
    /// let swe = script::script_with_extensions();
529
    ///
530
    /// let syriac = swe.get_script_extensions_set(Script::Syriac);
531
    ///
532
    /// assert!(!syriac.contains32(0x061E)); // ARABIC TRIPLE DOT PUNCTUATION MARK
533
    /// assert!(syriac.contains32(0x061F)); // ARABIC QUESTION MARK
534
    /// assert!(!syriac.contains32(0x0620)); // ARABIC LETTER KASHMIRI YEH
535
    ///
536
    /// assert!(syriac.contains32(0x0700)); // SYRIAC END OF PARAGRAPH
537
    /// assert!(syriac.contains32(0x074A)); // SYRIAC BARREKH
538
    /// assert!(!syriac.contains32(0x074B)); // unassigned
539
    /// assert!(syriac.contains32(0x074F)); // SYRIAC LETTER SOGDIAN FE
540
    /// assert!(!syriac.contains32(0x0750)); // ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW
541
    ///
542
    /// assert!(syriac.contains32(0x1DF8)); // COMBINING DOT ABOVE LEFT
543
    /// assert!(!syriac.contains32(0x1DF9)); // COMBINING WIDE INVERTED BRIDGE BELOW
544
    /// assert!(syriac.contains32(0x1DFA)); // COMBINING DOT BELOW LEFT
545
    /// assert!(!syriac.contains32(0x1DFB)); // COMBINING DELETION MARK
546
    /// ```
547
0
    pub fn get_script_extensions_set(self, script: Script) -> CodePointInversionList<'a> {
548
0
        CodePointInversionList::from_iter(self.get_script_extensions_ranges(script))
549
0
    }
550
}
551
552
impl ScriptWithExtensionsBorrowed<'static> {
553
    /// Cheaply converts a [`ScriptWithExtensionsBorrowed<'static>`] into a [`ScriptWithExtensions`].
554
    ///
555
    /// Note: Due to branching and indirection, using [`ScriptWithExtensions`] might inhibit some
556
    /// compile-time optimizations that are possible with [`ScriptWithExtensionsBorrowed`].
557
0
    pub const fn static_to_owned(self) -> ScriptWithExtensions {
558
0
        ScriptWithExtensions {
559
0
            data: DataPayload::from_static_ref(self.data),
560
0
        }
561
0
    }
562
}
563
564
/// Returns a [`ScriptWithExtensionsBorrowed`] struct that represents the data for the Script
565
/// and Script_Extensions properties.
566
///
567
/// ✨ *Enabled with the `compiled_data` Cargo feature.*
568
///
569
/// [📚 Help choosing a constructor](icu_provider::constructors)
570
///
571
/// # Examples
572
///
573
/// ```
574
/// use icu::properties::{script, Script};
575
/// let swe = script::script_with_extensions();
576
///
577
/// // get the `Script` property value
578
/// assert_eq!(swe.get_script_val(0x0640), Script::Common); // U+0640 ARABIC TATWEEL
579
/// assert_eq!(swe.get_script_val(0x0650), Script::Inherited); // U+0650 ARABIC KASRA
580
/// assert_eq!(swe.get_script_val(0x0660), Script::Arabic); // // U+0660 ARABIC-INDIC DIGIT ZERO
581
/// assert_eq!(swe.get_script_val(0xFDF2), Script::Arabic); // U+FDF2 ARABIC LIGATURE ALLAH ISOLATED FORM
582
///
583
/// // get the `Script_Extensions` property value
584
/// assert_eq!(
585
///     swe.get_script_extensions_val(0x0640) // U+0640 ARABIC TATWEEL
586
///         .iter().collect::<Vec<Script>>(),
587
///     vec![Script::Arabic, Script::Syriac, Script::Mandaic, Script::Manichaean,
588
///          Script::PsalterPahlavi, Script::Adlam, Script::HanifiRohingya, Script::Sogdian,
589
///          Script::OldUyghur]
590
/// );
591
/// assert_eq!(
592
///     swe.get_script_extensions_val('🥳' as u32) // U+1F973 FACE WITH PARTY HORN AND PARTY HAT
593
///         .iter().collect::<Vec<Script>>(),
594
///     vec![Script::Common]
595
/// );
596
/// assert_eq!(
597
///     swe.get_script_extensions_val(0x200D) // ZERO WIDTH JOINER
598
///         .iter().collect::<Vec<Script>>(),
599
///     vec![Script::Inherited]
600
/// );
601
/// assert_eq!(
602
///     swe.get_script_extensions_val('௫' as u32) // U+0BEB TAMIL DIGIT FIVE
603
///         .iter().collect::<Vec<Script>>(),
604
///     vec![Script::Tamil, Script::Grantha]
605
/// );
606
///
607
/// // check containment of a `Script` value in the `Script_Extensions` value
608
/// // U+0650 ARABIC KASRA
609
/// assert!(!swe.has_script(0x0650, Script::Inherited)); // main Script value
610
/// assert!(swe.has_script(0x0650, Script::Arabic));
611
/// assert!(swe.has_script(0x0650, Script::Syriac));
612
/// assert!(!swe.has_script(0x0650, Script::Thaana));
613
///
614
/// // get a `CodePointInversionList` for when `Script` value is contained in `Script_Extensions` value
615
/// let syriac = swe.get_script_extensions_set(Script::Syriac);
616
/// assert!(syriac.contains32(0x0650)); // ARABIC KASRA
617
/// assert!(!syriac.contains32(0x0660)); // ARABIC-INDIC DIGIT ZERO
618
/// assert!(!syriac.contains32(0xFDF2)); // ARABIC LIGATURE ALLAH ISOLATED FORM
619
/// assert!(syriac.contains32(0x0700)); // SYRIAC END OF PARAGRAPH
620
/// assert!(syriac.contains32(0x074A)); // SYRIAC BARREKH
621
/// ```
622
#[cfg(feature = "compiled_data")]
623
0
pub const fn script_with_extensions() -> ScriptWithExtensionsBorrowed<'static> {
624
0
    ScriptWithExtensionsBorrowed {
625
0
        data: crate::provider::Baked::SINGLETON_PROPS_SCX_V1,
626
0
    }
627
0
}
628
629
icu_provider::gen_any_buffer_data_constructors!(
630
    locale: skip,
631
    options: skip,
632
    result: Result<ScriptWithExtensions, PropertiesError>,
633
    #[cfg(skip)]
634
    functions: [
635
        script_with_extensions,
636
        load_script_with_extensions_with_any_provider,
637
        load_script_with_extensions_with_buffer_provider,
638
        load_script_with_extensions_unstable,
639
    ]
640
);
641
642
#[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, script_with_extensions)]
643
0
pub fn load_script_with_extensions_unstable(
644
0
    provider: &(impl DataProvider<ScriptWithExtensionsPropertyV1Marker> + ?Sized),
645
0
) -> Result<ScriptWithExtensions, PropertiesError> {
646
0
    Ok(ScriptWithExtensions::from_data(
647
0
        provider
648
0
            .load(Default::default())
649
0
            .and_then(DataResponse::take_payload)?,
650
    ))
651
0
}
Unexecuted instantiation: icu_properties::script::load_script_with_extensions_unstable::<icu_provider::any::DowncastingAnyProvider<icu_provider_adapters::empty::EmptyDataProvider>>
Unexecuted instantiation: icu_properties::script::load_script_with_extensions_unstable::<_>