icu_provider_source/properties/
bidi.rs
1use std::collections::HashSet;
6
7use crate::SourceDataProvider;
8use icu::properties::provider::PropertyEnumBidiMirroringGlyphV1;
9use icu_provider::prelude::*;
10
11#[cfg(any(feature = "use_wasm", feature = "use_icu4c"))]
12impl SourceDataProvider {
13 fn get_code_point_prop_map<'a>(
14 &'a self,
15 key: &str,
16 ) -> Result<&'a super::uprops_serde::code_point_prop::CodePointPropertyMap, DataError> {
17 self.icuexport()?
18 .read_and_parse_toml::<super::uprops_serde::code_point_prop::Main>(&format!(
19 "uprops/{}/{}.toml",
20 self.trie_type(),
21 key
22 ))?
23 .enum_property
24 .first()
25 .ok_or_else(|| DataErrorKind::MarkerNotFound.into_error())
26 }
27}
28
29impl DataProvider<PropertyEnumBidiMirroringGlyphV1> for SourceDataProvider {
32 #[cfg(any(feature = "use_wasm", feature = "use_icu4c"))]
33 fn load(
34 &self,
35 req: DataRequest,
36 ) -> Result<DataResponse<PropertyEnumBidiMirroringGlyphV1>, DataError> {
37 use icu::collections::codepointinvlist::CodePointInversionListBuilder;
38 use icu::collections::codepointtrie::CodePointTrie;
39 use icu::collections::codepointtrie::TrieType;
40 use icu::properties::props::BidiMirroringGlyph;
41 use icu::properties::props::BidiPairedBracketType;
42 use icu_codepointtrie_builder::{CodePointTrieBuilder, CodePointTrieBuilderData};
43 use icu_collections::codepointtrie::TrieValue;
44
45 self.check_req::<PropertyEnumBidiMirroringGlyphV1>(req)?;
46
47 let bidi_m_data = self.get_binary_prop_for_code_point_set("Bidi_M")?;
49 let mut bidi_m_builder = CodePointInversionListBuilder::new();
50 for (start, end) in &bidi_m_data.ranges {
51 bidi_m_builder.add_range32(start..=end);
52 }
53 let bidi_m_cpinvlist = bidi_m_builder.build();
54
55 let bmg_data = &self.get_code_point_prop_map("bmg")?.code_point_trie;
57 let bmg_trie = CodePointTrie::try_from(bmg_data).map_err(|e| {
58 DataError::custom("Could not parse CodePointTrie TOML").with_display_context(&e)
59 })?;
60
61 let bpt_data = &self.get_enumerated_prop("bpt")?.code_point_trie;
63 let bpt_trie = CodePointTrie::try_from(bpt_data).map_err(|e| {
64 DataError::custom("Could not parse CodePointTrie TOML").with_display_context(&e)
65 })?;
66
67 let trie_vals = (0..=(char::MAX as u32)).map(|cp| {
68 let mut r = BidiMirroringGlyph::default();
69 r.mirrored = bidi_m_cpinvlist.contains32(cp);
70 r.mirroring_glyph = r
71 .mirrored
72 .then_some(bmg_trie.get32(cp))
73 .filter(|&cp| cp as u32 != 0);
74 r.paired_bracket_type = match bpt_trie.get32(cp) {
75 1 => BidiPairedBracketType::Open,
76 2 => BidiPairedBracketType::Close,
77 _ => BidiPairedBracketType::None,
78 };
79 if r.mirrored && r.mirroring_glyph.is_none() {
80 log::trace!(
81 "Missing mirroring glyph: U+{cp:X}: {}",
82 char::try_from_u32(cp).unwrap()
83 );
84 }
85 r
86 });
87
88 Ok(DataResponse {
89 metadata: Default::default(),
90 payload: DataPayload::from_owned(
91 icu::properties::provider::PropertyCodePointMap::CodePointTrie(
92 CodePointTrieBuilder {
93 data: CodePointTrieBuilderData::ValuesByCodePoint(
94 &trie_vals.collect::<Vec<_>>(),
95 ),
96 default_value: BidiMirroringGlyph::default(),
97 error_value: BidiMirroringGlyph::default(),
98 trie_type: TrieType::Small,
99 }
100 .build(),
101 ),
102 ),
103 })
104 }
105
106 #[cfg(not(any(feature = "use_wasm", feature = "use_icu4c")))]
107 fn load(
108 &self,
109 req: DataRequest,
110 ) -> Result<DataResponse<PropertyEnumBidiMirroringGlyphV1>, DataError> {
111 self.check_req::<PropertyEnumBidiMirroringGlyphV1>(req)?;
112 return Err(DataError::custom(
113 "icu_provider_source must be built with use_icu4c or use_wasm to build Bidi auxiliary properties data",
114 ));
115 }
116}
117
118impl crate::IterableDataProviderCached<PropertyEnumBidiMirroringGlyphV1> for SourceDataProvider {
119 fn iter_ids_cached(&self) -> Result<HashSet<DataIdentifierCow<'static>>, DataError> {
120 Ok(HashSet::from_iter([Default::default()]))
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use icu::properties::props::{BidiMirroringGlyph, BidiPairedBracketType};
128
129 #[test]
130 fn test_bidi_data_provider() {
131 let provider = SourceDataProvider::new_testing();
132
133 let bidi_data =
134 icu::properties::CodePointMapData::<BidiMirroringGlyph>::try_new_unstable(&provider)
135 .unwrap();
136 let bidi_data = bidi_data.as_borrowed();
137
138 let close_paren = bidi_data.get(')');
139 assert_eq!(close_paren.mirroring_glyph, Some('('));
140 assert!(close_paren.mirrored);
141 let close_angle_bracket = bidi_data.get('>');
142 assert_eq!(close_angle_bracket.mirroring_glyph, Some('<'));
143 assert!(close_angle_bracket.mirrored);
144
145 let open_paren = bidi_data.get('(');
146 assert_eq!(open_paren.paired_bracket_type, BidiPairedBracketType::Open);
147 let open_angle_bracket = bidi_data.get('<');
148 assert_eq!(
149 open_angle_bracket.paired_bracket_type,
150 BidiPairedBracketType::None
151 );
152 }
153}