use std::collections::HashSet;
use crate::SourceDataProvider;
use icu::properties::provider::PropertyEnumBidiMirroringGlyphV1;
use icu_provider::prelude::*;
impl DataProvider<PropertyEnumBidiMirroringGlyphV1> for SourceDataProvider {
#[cfg(any(feature = "use_wasm", feature = "use_icu4c"))]
fn load(
&self,
req: DataRequest,
) -> Result<DataResponse<PropertyEnumBidiMirroringGlyphV1>, DataError> {
use super::ucd_helpers;
use icu::collections::codepointtrie::TrieType;
use icu::properties::props::BidiMirroringGlyph;
use icu::properties::props::BidiPairedBracketType;
use icu::properties::props::EnumeratedProperty;
use icu_codepointtrie_builder::CodePointTrieBuilder;
use std::collections::HashMap;
self.check_req::<PropertyEnumBidiMirroringGlyphV1>(req)?;
if let Some(t) = self
.rscd()?
.cpt_cache
.get(str::from_utf8(BidiMirroringGlyph::SHORT_NAME).unwrap())
{
let trie = t.downcast_ref::<icu::collections::codepointtrie::CodePointTrie<'static, BidiMirroringGlyph>>().unwrap().clone();
return Ok(DataResponse {
metadata: Default::default(),
payload: DataPayload::from_owned(
icu::properties::provider::PropertyCodePointMap::CodePointTrie(trie),
),
});
}
let bidi_m_cpinvlist = self.get_binary_prop("Bidi_Mirrored", "Bidi_M")?;
let bidi_mirroring = self
.rscd()?
.parse_ucd_lines("ucd/BidiMirroring.txt")?
.filter_map(|line| {
let mut fields = line.skip_missing_rule()?.fields();
let cp_range = fields.next().unwrap().trim();
let prop_value = fields.next().unwrap().trim();
let value = ucd_helpers::parse_cp(prop_value);
let cp = ucd_helpers::parse_cp(cp_range);
Some((cp, char::from_u32(value).unwrap()))
})
.collect::<HashMap<_, _>>();
let paired_brackets = self.rscd()?.parse_ucd_lines("ucd/BidiBrackets.txt")?.filter_map(|line| {
let mut parts = line.skip_missing_rule()?.fields();
let cp = ucd_helpers::parse_cp(parts.next().unwrap().trim());
let mirror = ucd_helpers::parse_cp(parts.next().unwrap().trim());
if bidi_mirroring[&cp] as u32 != mirror {
log::warn!(
"BidiMirroring.txt and BidiBrackets.txt disagree for U+{cp:X}: {:?} vs U+{mirror:X}",
bidi_mirroring[&cp]
);
}
let typ = match parts.next().unwrap().trim() {
"o" => BidiPairedBracketType::Open,
"c" => BidiPairedBracketType::Close,
"n" => BidiPairedBracketType::None,
_ => unreachable!(),
};
Some((cp, typ))
}).collect::<HashMap<_, _>>();
let mut builder = CodePointTrieBuilder::new(
BidiMirroringGlyph::default(),
BidiMirroringGlyph::default(),
TrieType::Small,
);
for cp in 0..=(char::MAX as u32) {
if !bidi_m_cpinvlist.contains32(cp) {
continue;
}
let mirroring_glyph = bidi_mirroring.get(&cp).copied();
if mirroring_glyph.is_none() {
log::trace!(
"Missing mirroring glyph: U+{cp:X}: {}",
char::from_u32(cp).unwrap()
);
};
let paired_bracket_type = paired_brackets
.get(&cp)
.copied()
.unwrap_or(BidiPairedBracketType::None);
builder.set_value(
cp,
BidiMirroringGlyph {
mirrored: true,
mirroring_glyph,
paired_bracket_type,
},
);
}
let trie = builder.build();
self.rscd()?.cpt_cache.insert(
str::from_utf8(BidiMirroringGlyph::SHORT_NAME).unwrap(),
Box::new(trie.clone()),
);
Ok(DataResponse {
metadata: Default::default(),
payload: DataPayload::from_owned(
icu::properties::provider::PropertyCodePointMap::CodePointTrie(trie),
),
})
}
#[cfg(not(any(feature = "use_wasm", feature = "use_icu4c")))]
fn load(
&self,
req: DataRequest,
) -> Result<DataResponse<PropertyEnumBidiMirroringGlyphV1>, DataError> {
self.check_req::<PropertyEnumBidiMirroringGlyphV1>(req)?;
return Err(DataError::custom(
"icu_provider_source must be built with `use_icu4c` or `use_wasm` to build enumerated properties data",
));
}
}
impl crate::IterableDataProviderCached<PropertyEnumBidiMirroringGlyphV1> for SourceDataProvider {
fn iter_ids_cached(&self) -> Result<HashSet<DataIdentifierCow<'static>>, DataError> {
Ok(HashSet::from_iter([Default::default()]))
}
}
#[cfg(test)]
mod tests {
use super::*;
use icu::properties::props::{BidiMirroringGlyph, BidiPairedBracketType};
#[test]
fn test_bidi_data_provider() {
let provider = SourceDataProvider::new_testing();
let bidi_data =
icu::properties::CodePointMapData::<BidiMirroringGlyph>::try_new_unstable(&provider)
.unwrap();
let bidi_data = bidi_data.as_borrowed();
let close_paren = bidi_data.get(')');
assert_eq!(close_paren.mirroring_glyph, Some('('));
assert!(close_paren.mirrored);
let close_angle_bracket = bidi_data.get('>');
assert_eq!(close_angle_bracket.mirroring_glyph, Some('<'));
assert!(close_angle_bracket.mirrored);
let open_paren = bidi_data.get('(');
assert_eq!(open_paren.paired_bracket_type, BidiPairedBracketType::Open);
let open_angle_bracket = bidi_data.get('<');
assert_eq!(
open_angle_bracket.paired_bracket_type,
BidiPairedBracketType::None
);
}
}