icu_properties/
maps.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//! The functions in this module return a [`CodePointMapData`] representing, for
6//! each code point in the entire range of code points, the property values
7//! for a particular Unicode property.
8//!
9//! The descriptions of most properties are taken from [`TR44`], the documentation for the
10//! Unicode Character Database.
11//!
12//! [`TR44`]: https://www.unicode.org/reports/tr44
13
14#[cfg(doc)]
15use super::*;
16use crate::error::PropertiesError;
17use crate::provider::*;
18use crate::sets::CodePointSetData;
19use core::marker::PhantomData;
20use core::ops::RangeInclusive;
21use icu_collections::codepointtrie::{CodePointMapRange, CodePointTrie, TrieValue};
22use icu_provider::prelude::*;
23use zerovec::ZeroVecError;
24
25/// A wrapper around code point map data. It is returned by APIs that return Unicode
26/// property data in a map-like form, ex: enumerated property value data keyed
27/// by code point. Access its data via the borrowed version,
28/// [`CodePointMapDataBorrowed`].
29#[derive(Debug, Clone)]
30pub struct CodePointMapData<T: TrieValue> {
31    data: DataPayload<ErasedMaplikeMarker<T>>,
32}
33
34/// Private marker type for CodePointMapData
35/// to work for all same-value map properties at once
36#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
37struct ErasedMaplikeMarker<T>(PhantomData<T>);
38impl<T: TrieValue> DataMarker for ErasedMaplikeMarker<T> {
39    type Yokeable = PropertyCodePointMapV1<'static, T>;
40}
41
42impl<T: TrieValue> CodePointMapData<T> {
43    /// Construct a borrowed version of this type that can be queried.
44    ///
45    /// This avoids a potential small underlying cost per API call (like `get()`) by consolidating it
46    /// up front.
47    ///
48    /// This owned version if returned by functions that use a runtime data provider.
49    #[inline]
50    pub fn as_borrowed(&self) -> CodePointMapDataBorrowed<'_, T> {
51        CodePointMapDataBorrowed {
52            map: self.data.get(),
53        }
54    }
55
56    /// Convert this map to a map around another type
57    ///
58    /// Typically useful for type-erasing maps into maps around integers.
59    ///
60    /// # Panics
61    /// Will panic if T and P are different sizes
62    ///
63    /// # Example
64    ///
65    /// ```
66    /// use icu::properties::{maps, GeneralCategory};
67    ///
68    /// let data = maps::general_category().static_to_owned();
69    ///
70    /// let gc = data.try_into_converted::<u8>().unwrap();
71    /// let gc = gc.as_borrowed();
72    ///
73    /// assert_eq!(gc.get('木'), GeneralCategory::OtherLetter as u8);  // U+6728
74    /// assert_eq!(gc.get('🎃'), GeneralCategory::OtherSymbol as u8);  // U+1F383 JACK-O-LANTERN
75    /// ```
76    pub fn try_into_converted<P>(self) -> Result<CodePointMapData<P>, ZeroVecError>
77    where
78        P: TrieValue,
79    {
80        self.data
81            .try_map_project::<ErasedMaplikeMarker<P>, _, _>(move |data, _| {
82                data.try_into_converted()
83            })
84            .map(CodePointMapData::from_data)
85    }
86
87    /// Construct a new one from loaded data
88    ///
89    /// Typically it is preferable to use getters like [`load_general_category()`] instead
90    pub fn from_data<M>(data: DataPayload<M>) -> Self
91    where
92        M: DataMarker<Yokeable = PropertyCodePointMapV1<'static, T>>,
93    {
94        Self { data: data.cast() }
95    }
96
97    /// Construct a new one an owned [`CodePointTrie`]
98    pub fn from_code_point_trie(trie: CodePointTrie<'static, T>) -> Self {
99        let set = PropertyCodePointMapV1::from_code_point_trie(trie);
100        CodePointMapData::from_data(DataPayload::<ErasedMaplikeMarker<T>>::from_owned(set))
101    }
102
103    /// Convert this type to a [`CodePointTrie`] as a borrowed value.
104    ///
105    /// The data backing this is extensible and supports multiple implementations.
106    /// Currently it is always [`CodePointTrie`]; however in the future more backends may be
107    /// added, and users may select which at data generation time.
108    ///
109    /// This method returns an `Option` in order to return `None` when the backing data provider
110    /// cannot return a [`CodePointTrie`], or cannot do so within the expected constant time
111    /// constraint.
112    pub fn as_code_point_trie(&self) -> Option<&CodePointTrie<'_, T>> {
113        self.data.get().as_code_point_trie()
114    }
115
116    /// Convert this type to a [`CodePointTrie`], borrowing if possible,
117    /// otherwise allocating a new [`CodePointTrie`].
118    ///
119    /// The data backing this is extensible and supports multiple implementations.
120    /// Currently it is always [`CodePointTrie`]; however in the future more backends may be
121    /// added, and users may select which at data generation time.
122    ///
123    /// The performance of the conversion to this specific return type will vary
124    /// depending on the data structure that is backing `self`.
125    pub fn to_code_point_trie(&self) -> CodePointTrie<'_, T> {
126        self.data.get().to_code_point_trie()
127    }
128}
129
130/// A borrowed wrapper around code point set data, returned by
131/// [`CodePointSetData::as_borrowed()`]. More efficient to query.
132#[derive(Clone, Copy, Debug)]
133pub struct CodePointMapDataBorrowed<'a, T: TrieValue> {
134    map: &'a PropertyCodePointMapV1<'a, T>,
135}
136
137impl<'a, T: TrieValue> CodePointMapDataBorrowed<'a, T> {
138    /// Get the value this map has associated with code point `ch`
139    ///
140    /// # Example
141    ///
142    /// ```
143    /// use icu::properties::{maps, GeneralCategory};
144    ///
145    /// let gc = maps::general_category();
146    ///
147    /// assert_eq!(gc.get('木'), GeneralCategory::OtherLetter);  // U+6728
148    /// assert_eq!(gc.get('🎃'), GeneralCategory::OtherSymbol);  // U+1F383 JACK-O-LANTERN
149    /// ```
150    pub fn get(self, ch: char) -> T {
151        self.map.get32(ch as u32)
152    }
153
154    /// Get the value this map has associated with code point `ch`
155    ///
156    /// # Example
157    ///
158    /// ```
159    /// use icu::properties::{maps, GeneralCategory};
160    ///
161    /// let gc = maps::general_category();
162    ///
163    /// assert_eq!(gc.get32(0x6728), GeneralCategory::OtherLetter);  // U+6728 (木)
164    /// assert_eq!(gc.get32(0x1F383), GeneralCategory::OtherSymbol);  // U+1F383 JACK-O-LANTERN
165    /// ```
166    pub fn get32(self, ch: u32) -> T {
167        self.map.get32(ch)
168    }
169
170    /// Get a [`CodePointSetData`] for all elements corresponding to a particular value
171    ///
172    /// # Example
173    ///
174    /// ```
175    /// use icu::properties::{maps, GeneralCategory};
176    ///
177    /// let gc = maps::general_category();
178    ///
179    /// let other_letter_set_data =
180    ///     gc.get_set_for_value(GeneralCategory::OtherLetter);
181    /// let other_letter_set = other_letter_set_data.as_borrowed();
182    ///
183    /// assert!(other_letter_set.contains('木')); // U+6728
184    /// assert!(!other_letter_set.contains('🎃')); // U+1F383 JACK-O-LANTERN
185    /// ```
186    pub fn get_set_for_value(self, value: T) -> CodePointSetData {
187        let set = self.map.get_set_for_value(value);
188        CodePointSetData::from_code_point_inversion_list(set)
189    }
190
191    /// Yields an [`Iterator`] returning ranges of consecutive code points that
192    /// share the same value in the [`CodePointMapData`].
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// use icu::properties::maps;
198    /// use icu::properties::GeneralCategory;
199    ///
200    /// let gc = maps::general_category();
201    /// let mut ranges = gc.iter_ranges();
202    /// let next = ranges.next().unwrap();
203    /// assert_eq!(next.range, 0..=31);
204    /// assert_eq!(next.value, GeneralCategory::Control);
205    /// let next = ranges.next().unwrap();
206    /// assert_eq!(next.range, 32..=32);
207    /// assert_eq!(next.value, GeneralCategory::SpaceSeparator);
208    /// ```
209    pub fn iter_ranges(self) -> impl Iterator<Item = CodePointMapRange<T>> + 'a {
210        self.map.iter_ranges()
211    }
212
213    /// Yields an [`Iterator`] returning ranges of consecutive code points that
214    /// share the same value `v` in the [`CodePointMapData`].
215    ///
216    /// # Examples
217    ///
218    ///
219    /// ```
220    /// use icu::properties::maps;
221    /// use icu::properties::GeneralCategory;
222    ///
223    /// let gc = maps::general_category();
224    /// let mut ranges = gc.iter_ranges_for_value(GeneralCategory::UppercaseLetter);
225    /// assert_eq!(ranges.next().unwrap(), 'A' as u32..='Z' as u32);
226    /// assert_eq!(ranges.next().unwrap(), 'À' as u32..='Ö' as u32);
227    /// assert_eq!(ranges.next().unwrap(), 'Ø' as u32..='Þ' as u32);
228    /// ```
229    pub fn iter_ranges_for_value(self, val: T) -> impl Iterator<Item = RangeInclusive<u32>> + 'a {
230        self.map
231            .iter_ranges()
232            .filter(move |r| r.value == val)
233            .map(|r| r.range)
234    }
235
236    /// Yields an [`Iterator`] returning ranges of consecutive code points that
237    /// do *not* have the value `v` in the [`CodePointMapData`].
238    pub fn iter_ranges_for_value_complemented(
239        self,
240        val: T,
241    ) -> impl Iterator<Item = RangeInclusive<u32>> + 'a {
242        self.map
243            .iter_ranges_mapped(move |value| value != val)
244            .filter(|v| v.value)
245            .map(|v| v.range)
246    }
247
248    /// Exposed for FFI needs, could be exposed in general in the future but we should
249    /// have a use case first.
250    ///
251    /// FFI needs this since it operates on erased maps and can't use `iter_ranges_for_group()`
252    #[doc(hidden)]
253    pub fn iter_ranges_mapped<U: Eq + 'a>(
254        self,
255        predicate: impl FnMut(T) -> U + Copy + 'a,
256    ) -> impl Iterator<Item = CodePointMapRange<U>> + 'a {
257        self.map.iter_ranges_mapped(predicate)
258    }
259}
260
261impl<T: TrieValue> CodePointMapDataBorrowed<'static, T> {
262    /// Cheaply converts a [`CodePointMapDataBorrowed<'static>`] into a [`CodePointMapData`].
263    ///
264    /// Note: Due to branching and indirection, using [`CodePointMapData`] might inhibit some
265    /// compile-time optimizations that are possible with [`CodePointMapDataBorrowed`].
266    pub const fn static_to_owned(self) -> CodePointMapData<T> {
267        CodePointMapData {
268            data: DataPayload::from_static_ref(self.map),
269        }
270    }
271}
272
273impl<'a> CodePointMapDataBorrowed<'a, crate::GeneralCategory> {
274    /// Yields an [`Iterator`] returning ranges of consecutive code points that
275    /// have a `General_Category` value belonging to the specified [`GeneralCategoryGroup`]
276    ///
277    /// # Examples
278    ///
279    ///
280    /// ```
281    /// use core::ops::RangeInclusive;
282    /// use icu::properties::maps::{self, CodePointMapData};
283    /// use icu::properties::GeneralCategoryGroup;
284    ///
285    /// let gc = maps::general_category();
286    /// let mut ranges = gc.iter_ranges_for_group(GeneralCategoryGroup::Letter);
287    /// assert_eq!(ranges.next().unwrap(), 'A' as u32..='Z' as u32);
288    /// assert_eq!(ranges.next().unwrap(), 'a' as u32..='z' as u32);
289    /// assert_eq!(ranges.next().unwrap(), 'ª' as u32..='ª' as u32);
290    /// assert_eq!(ranges.next().unwrap(), 'µ' as u32..='µ' as u32);
291    /// assert_eq!(ranges.next().unwrap(), 'º' as u32..='º' as u32);
292    /// assert_eq!(ranges.next().unwrap(), 'À' as u32..='Ö' as u32);
293    /// assert_eq!(ranges.next().unwrap(), 'Ø' as u32..='ö' as u32);
294    /// ```
295    pub fn iter_ranges_for_group(
296        self,
297        group: crate::GeneralCategoryGroup,
298    ) -> impl Iterator<Item = RangeInclusive<u32>> + 'a {
299        self.map
300            .iter_ranges_mapped(move |value| group.contains(value))
301            .filter(|v| v.value)
302            .map(|v| v.range)
303    }
304}
305
306macro_rules! make_map_property {
307    (
308        // currently unused
309        property: $prop_name:expr;
310        // currently unused
311        marker: $marker_name:ident;
312        value: $value_ty:path;
313        keyed_data_marker: $keyed_data_marker:ty;
314        func:
315        $(#[$doc:meta])*
316        $vis2:vis const $constname:ident => $singleton:ident;
317        $vis:vis fn $name:ident();
318    ) => {
319        #[doc = concat!("A version of [`", stringify!($constname), "()`] that uses custom data provided by a [`DataProvider`].")]
320        ///
321        /// Note that this will return an owned version of the data. Functionality is available on
322        /// the borrowed version, accessible through [`CodePointMapData::as_borrowed`].
323        ///
324        /// [📚 Help choosing a constructor](icu_provider::constructors)
325        $vis fn $name(
326            provider: &(impl DataProvider<$keyed_data_marker> + ?Sized)
327        ) -> Result<CodePointMapData<$value_ty>, PropertiesError> {
328            Ok(provider.load(Default::default()).and_then(DataResponse::take_payload).map(CodePointMapData::from_data)?)
329        }
330        $(#[$doc])*
331        #[cfg(feature = "compiled_data")]
332        pub const fn $constname() -> CodePointMapDataBorrowed<'static, $value_ty> {
333            CodePointMapDataBorrowed {
334                map: crate::provider::Baked::$singleton
335            }
336        }
337    };
338}
339
340make_map_property! {
341    property: "General_Category";
342    marker: GeneralCategoryProperty;
343    value: crate::GeneralCategory;
344    keyed_data_marker: GeneralCategoryV1Marker;
345    func:
346    /// Return a [`CodePointMapDataBorrowed`] for the General_Category Unicode enumerated property. See [`GeneralCategory`].
347    ///
348    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
349    ///
350    /// [📚 Help choosing a constructor](icu_provider::constructors)
351    ///
352    /// # Example
353    ///
354    /// ```
355    /// use icu::properties::{maps, GeneralCategory};
356    ///
357    /// assert_eq!(maps::general_category().get('木'), GeneralCategory::OtherLetter);  // U+6728
358    /// assert_eq!(maps::general_category().get('🎃'), GeneralCategory::OtherSymbol);  // U+1F383 JACK-O-LANTERN
359    /// ```
360    pub const general_category => SINGLETON_PROPS_GC_V1;
361    pub fn load_general_category();
362}
363
364make_map_property! {
365    property: "Bidi_Class";
366    marker: BidiClassProperty;
367    value: crate::BidiClass;
368    keyed_data_marker: BidiClassV1Marker;
369    func:
370    /// Return a [`CodePointMapDataBorrowed`] for the Bidi_Class Unicode enumerated property. See [`BidiClass`].
371    ///
372    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
373    ///
374    /// [📚 Help choosing a constructor](icu_provider::constructors)
375    ///
376    /// # Example
377    ///
378    /// ```
379    /// use icu::properties::{maps, BidiClass};
380    ///
381    /// assert_eq!(maps::bidi_class().get('y'), BidiClass::LeftToRight);  // U+0079
382    /// assert_eq!(maps::bidi_class().get('ع'), BidiClass::ArabicLetter);  // U+0639
383    /// ```
384    pub const bidi_class => SINGLETON_PROPS_BC_V1;
385    pub fn load_bidi_class();
386}
387
388make_map_property! {
389    property: "Script";
390    marker: ScriptProperty;
391    value: crate::Script;
392    keyed_data_marker: ScriptV1Marker;
393    func:
394    /// Return a [`CodePointMapDataBorrowed`] for the Script Unicode enumerated property. See [`Script`].
395    ///
396    /// **Note:** Some code points are associated with multiple scripts. If you are trying to
397    /// determine whether a code point belongs to a certain script, you should use
398    /// [`load_script_with_extensions_unstable`] and [`ScriptWithExtensionsBorrowed::has_script`]
399    /// instead of this function.
400    ///
401    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
402    ///
403    /// [📚 Help choosing a constructor](icu_provider::constructors)
404    ///
405    /// # Example
406    ///
407    /// ```
408    /// use icu::properties::{maps, Script};
409    ///
410    /// assert_eq!(maps::script().get('木'), Script::Han);  // U+6728
411    /// assert_eq!(maps::script().get('🎃'), Script::Common);  // U+1F383 JACK-O-LANTERN
412    /// ```
413    /// [`load_script_with_extensions_unstable`]: crate::script::load_script_with_extensions_unstable
414    /// [`ScriptWithExtensionsBorrowed::has_script`]: crate::script::ScriptWithExtensionsBorrowed::has_script
415    pub const script => SINGLETON_PROPS_SC_V1;
416    pub fn load_script();
417}
418
419make_map_property! {
420    property: "Hangul_Syllable_Type";
421    marker: HangulSyllableTypeProperty;
422    value: crate::HangulSyllableType;
423    keyed_data_marker: HangulSyllableTypeV1Marker;
424    func:
425    /// Returns a [`CodePointMapDataBorrowed`] for the Hangul_Syllable_Type
426    /// Unicode enumerated property. See [`HangulSyllableType`].
427    ///
428    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
429    ///
430    /// [📚 Help choosing a constructor](icu_provider::constructors)
431    ///
432    /// # Example
433    ///
434    /// ```
435    /// use icu::properties::{maps, HangulSyllableType};
436    ///
437    /// assert_eq!(maps::hangul_syllable_type().get('ᄀ'), HangulSyllableType::LeadingJamo);  // U+1100
438    /// assert_eq!(maps::hangul_syllable_type().get('가'), HangulSyllableType::LeadingVowelSyllable);  // U+AC00
439    /// ```
440
441    pub const hangul_syllable_type => SINGLETON_PROPS_HST_V1;
442    pub fn load_hangul_syllable_type();
443}
444
445make_map_property! {
446    property: "East_Asian_Width";
447    marker: EastAsianWidthProperty;
448    value: crate::EastAsianWidth;
449    keyed_data_marker: EastAsianWidthV1Marker;
450    func:
451    /// Return a [`CodePointMapDataBorrowed`] for the East_Asian_Width Unicode enumerated
452    /// property. See [`EastAsianWidth`].
453    ///
454    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
455    ///
456    /// [📚 Help choosing a constructor](icu_provider::constructors)
457    ///
458    /// # Example
459    ///
460    /// ```
461    /// use icu::properties::{maps, EastAsianWidth};
462    ///
463    /// assert_eq!(maps::east_asian_width().get('ア'), EastAsianWidth::Halfwidth); // U+FF71: Halfwidth Katakana Letter A
464    /// assert_eq!(maps::east_asian_width().get('ア'), EastAsianWidth::Wide); //U+30A2: Katakana Letter A
465    /// ```
466    pub const east_asian_width => SINGLETON_PROPS_EA_V1;
467    pub fn load_east_asian_width();
468}
469
470make_map_property! {
471    property: "Line_Break";
472    marker: LineBreakProperty;
473    value: crate::LineBreak;
474    keyed_data_marker: LineBreakV1Marker;
475    func:
476    /// Return a [`CodePointMapDataBorrowed`] for the Line_Break Unicode enumerated
477    /// property. See [`LineBreak`].
478    ///
479    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
480    ///
481    /// [📚 Help choosing a constructor](icu_provider::constructors)
482    ///
483    /// **Note:** Use `icu::segmenter` for an all-in-one break iterator implementation.
484    ///
485    /// # Example
486    ///
487    /// ```
488    /// use icu::properties::{maps, LineBreak};
489    ///
490    /// assert_eq!(maps::line_break().get(')'), LineBreak::CloseParenthesis); // U+0029: Right Parenthesis
491    /// assert_eq!(maps::line_break().get('ぁ'), LineBreak::ConditionalJapaneseStarter); //U+3041: Hiragana Letter Small A
492    /// ```
493    pub const line_break => SINGLETON_PROPS_LB_V1;
494    pub fn load_line_break();
495}
496
497make_map_property! {
498    property: "Grapheme_Cluster_Break";
499    marker: GraphemeClusterBreakProperty;
500    value: crate::GraphemeClusterBreak;
501    keyed_data_marker: GraphemeClusterBreakV1Marker;
502    func:
503    /// Return a [`CodePointMapDataBorrowed`] for the Grapheme_Cluster_Break Unicode enumerated
504    /// property. See [`GraphemeClusterBreak`].
505    ///
506    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
507    ///
508    /// [📚 Help choosing a constructor](icu_provider::constructors)
509    ///
510    /// **Note:** Use `icu::segmenter` for an all-in-one break iterator implementation.
511    ///
512    /// # Example
513    ///
514    /// ```
515    /// use icu::properties::{maps, GraphemeClusterBreak};
516    ///
517    /// assert_eq!(maps::grapheme_cluster_break().get('🇦'), GraphemeClusterBreak::RegionalIndicator); // U+1F1E6: Regional Indicator Symbol Letter A
518    /// assert_eq!(maps::grapheme_cluster_break().get('ำ'), GraphemeClusterBreak::SpacingMark); //U+0E33: Thai Character Sara Am
519    /// ```
520    pub const grapheme_cluster_break => SINGLETON_PROPS_GCB_V1;
521    pub fn load_grapheme_cluster_break();
522}
523
524make_map_property! {
525    property: "Word_Break";
526    marker: WordBreakProperty;
527    value: crate::WordBreak;
528    keyed_data_marker: WordBreakV1Marker;
529    func:
530    /// Return a [`CodePointMapDataBorrowed`] for the Word_Break Unicode enumerated
531    /// property. See [`WordBreak`].
532    ///
533    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
534    ///
535    /// [📚 Help choosing a constructor](icu_provider::constructors)
536    ///
537    /// **Note:** Use `icu::segmenter` for an all-in-one break iterator implementation.
538    ///
539    /// # Example
540    ///
541    /// ```
542    /// use icu::properties::{maps, WordBreak};
543    ///
544    /// assert_eq!(maps::word_break().get('.'), WordBreak::MidNumLet); // U+002E: Full Stop
545    /// assert_eq!(maps::word_break().get(','), WordBreak::MidNum); // U+FF0C: Fullwidth Comma
546    /// ```
547    pub const word_break => SINGLETON_PROPS_WB_V1;
548    pub fn load_word_break();
549}
550
551make_map_property! {
552    property: "Sentence_Break";
553    marker: SentenceBreakProperty;
554    value: crate::SentenceBreak;
555    keyed_data_marker: SentenceBreakV1Marker;
556    func:
557    /// Return a [`CodePointMapDataBorrowed`] for the Sentence_Break Unicode enumerated
558    /// property. See [`SentenceBreak`].
559    ///
560    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
561    ///
562    /// [📚 Help choosing a constructor](icu_provider::constructors)
563    ///
564    /// **Note:** Use `icu::segmenter` for an all-in-one break iterator implementation.
565    ///
566    /// # Example
567    ///
568    /// ```
569    /// use icu::properties::{maps, SentenceBreak};
570    ///
571    /// assert_eq!(maps::sentence_break().get('9'), SentenceBreak::Numeric); // U+FF19: Fullwidth Digit Nine
572    /// assert_eq!(maps::sentence_break().get(','), SentenceBreak::SContinue); // U+002C: Comma
573    /// ```
574    pub const sentence_break => SINGLETON_PROPS_SB_V1;
575    pub fn load_sentence_break();
576}
577
578make_map_property! {
579    property: "Canonical_Combining_Class";
580    marker: CanonicalCombiningClassProperty;
581    value: crate::CanonicalCombiningClass;
582    keyed_data_marker: CanonicalCombiningClassV1Marker;
583    func:
584    /// Return a [`CodePointMapData`] for the Canonical_Combining_Class Unicode property. See
585    /// [`CanonicalCombiningClass`].
586    ///
587    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
588    ///
589    /// [📚 Help choosing a constructor](icu_provider::constructors)
590    ///
591    /// **Note:** See `icu::normalizer::CanonicalCombiningClassMap` for the preferred API
592    /// to look up the Canonical_Combining_Class property by scalar value.
593    ///
594    /// # Example
595    ///
596    /// ```
597    /// use icu::properties::{maps, CanonicalCombiningClass};
598    ///
599    /// assert_eq!(maps::canonical_combining_class().get('a'), CanonicalCombiningClass::NotReordered); // U+0061: LATIN SMALL LETTER A
600    /// assert_eq!(maps::canonical_combining_class().get32(0x0301), CanonicalCombiningClass::Above); // U+0301: COMBINING ACUTE ACCENT
601    /// ```
602    pub const canonical_combining_class => SINGLETON_PROPS_CCC_V1;
603    pub fn load_canonical_combining_class();
604}
605
606make_map_property! {
607    property: "Indic_Syllabic_Category";
608    marker: IndicSyllabicCategoryProperty;
609    value: crate::IndicSyllabicCategory;
610    keyed_data_marker: IndicSyllabicCategoryV1Marker;
611    func:
612    /// Return a [`CodePointMapData`] for the Indic_Syllabic_Category Unicode property. See
613    /// [`IndicSyllabicCategory`].
614    ///
615    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
616    ///
617    /// [📚 Help choosing a constructor](icu_provider::constructors)
618    ///
619    /// # Example
620    ///
621    /// ```
622    /// use icu::properties::{maps, IndicSyllabicCategory};
623    ///
624    /// assert_eq!(maps::indic_syllabic_category().get('a'), IndicSyllabicCategory::Other);
625    /// assert_eq!(maps::indic_syllabic_category().get32(0x0900), IndicSyllabicCategory::Bindu); // U+0900: DEVANAGARI SIGN INVERTED CANDRABINDU
626    /// ```
627    pub const indic_syllabic_category => SINGLETON_PROPS_INSC_V1;
628    pub fn load_indic_syllabic_category();
629}
630
631make_map_property! {
632    property: "Joining_Type";
633    marker: JoiningTypeProperty;
634    value: crate::JoiningType;
635    keyed_data_marker: JoiningTypeV1Marker;
636    func:
637    /// Return a [`CodePointMapDataBorrowed`] for the Joining_Type Unicode enumerated
638    /// property. See [`JoiningType`].
639    ///
640    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
641    ///
642    /// [📚 Help choosing a constructor](icu_provider::constructors)
643    ///
644    /// # Example
645    ///
646    /// ```
647    /// use icu::properties::{maps, JoiningType};
648    ///
649    /// assert_eq!(maps::joining_type().get('ؠ'), JoiningType::DualJoining); // U+0620: Arabic Letter Kashmiri Yeh
650    /// assert_eq!(maps::joining_type().get('𐫍'), JoiningType::LeftJoining); // U+10ACD: Manichaean Letter Heth
651    /// ```
652    pub const joining_type => SINGLETON_PROPS_JT_V1;
653    pub fn load_joining_type();
654}