use crate::uprops_helpers;
use crate::uprops_serde::script_extensions::ScriptExtensionsProperty;
use icu_codepointtrie::CodePointTrie;
use icu_properties::provider::{ScriptExtensionsPropertyV1, ScriptExtensionsPropertyV1Marker};
use icu_properties::script::{ScriptExtensions, ScriptWithExt};
use icu_properties::Script;
use icu_provider::prelude::*;
use std::convert::TryFrom;
use std::path::Path;
use zerovec::{VarZeroVec, ZeroSlice, ZeroVec};
pub struct ScriptExtensionsPropertyProvider {
data: ScriptExtensionsProperty,
}
impl ScriptExtensionsPropertyProvider {
pub fn try_new(root_dir: &Path) -> eyre::Result<Self> {
let data = uprops_helpers::load_script_extensions_from_dir(root_dir)?;
Ok(Self { data })
}
}
impl TryFrom<&ScriptExtensionsProperty> for ScriptExtensions<'static> {
type Error = DataError;
fn try_from(
scx_data: &ScriptExtensionsProperty,
) -> Result<ScriptExtensions<'static>, DataError> {
let cpt_data = &scx_data.code_point_trie;
let scx_array_data = &scx_data.script_code_array;
let trie = CodePointTrie::<ScriptWithExt>::try_from(cpt_data)?;
let ule_scx_array_data: Vec<ZeroVec<Script>> = scx_array_data
.iter()
.map(|v| v.iter().map(|i| Script(*i)).collect::<ZeroVec<Script>>())
.collect::<Vec<ZeroVec<Script>>>();
let scx_vzv: VarZeroVec<ZeroSlice<Script>> =
VarZeroVec::from(ule_scx_array_data.as_slice());
ScriptExtensions::try_new(trie, scx_vzv).map_err(|e| {
DataError::custom("Could not create ScriptExtensions from a trie and scx_vzv")
.with_error_context(&e)
})
}
}
impl TryFrom<&ScriptExtensionsProperty> for ScriptExtensionsPropertyV1<'static> {
type Error = DataError;
fn try_from(
scx_data: &ScriptExtensionsProperty,
) -> Result<ScriptExtensionsPropertyV1<'static>, DataError> {
let scx = ScriptExtensions::try_from(scx_data);
scx.map(|s| ScriptExtensionsPropertyV1 { data: s })
}
}
impl DataProvider<ScriptExtensionsPropertyV1Marker> for ScriptExtensionsPropertyProvider {
fn load_payload(
&self,
req: &DataRequest,
) -> Result<DataResponse<ScriptExtensionsPropertyV1Marker>, DataError> {
if uprops_helpers::get_last_component_no_version(&req.resource_path.key) != "scx" {
return Err(DataErrorKind::MissingResourceKey.with_req(req));
}
let source_scx_data = &self.data;
let data_struct = ScriptExtensionsPropertyV1::try_from(source_scx_data)?;
Ok(DataResponse {
metadata: DataResponseMetadata::default(),
payload: Some(DataPayload::from_owned(data_struct)),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use icu_properties::provider::key;
#[test]
fn test_script_val_from_script_extensions() {
let root_dir = icu_testdata::paths::uprops_toml_root();
let provider = ScriptExtensionsPropertyProvider::try_new(&root_dir)
.expect("TOML should load successfully");
let payload: DataPayload<ScriptExtensionsPropertyV1Marker> = provider
.load_payload(&DataRequest {
resource_path: ResourcePath {
key: key::SCRIPT_EXTENSIONS_V1,
options: ResourceOptions::default(),
},
})
.expect("The data should be valid")
.take_payload()
.expect("Loading was successful");
let scx: &ScriptExtensions = &payload.get().data;
assert_eq!(scx.get_script_val('𐓐' as u32), Script::Osage); assert_eq!(scx.get_script_val('🥳' as u32), Script::Common); assert_eq!(scx.get_script_val(0x200D), Script::Inherited); assert_eq!(scx.get_script_val('௫' as u32), Script::Tamil); assert_eq!(scx.get_script_val(0x11303), Script::Grantha); assert_eq!(scx.get_script_val(0x30A0), Script::Common); }
#[test]
fn test_scx_array_from_script_extensions() {
use zerovec::ZeroVec;
let root_dir = icu_testdata::paths::uprops_toml_root();
let provider = ScriptExtensionsPropertyProvider::try_new(&root_dir)
.expect("TOML should load successfully");
let payload: DataPayload<ScriptExtensionsPropertyV1Marker> = provider
.load_payload(&DataRequest {
resource_path: ResourcePath {
key: key::SCRIPT_EXTENSIONS_V1,
options: ResourceOptions::default(),
},
})
.expect("The data should be valid")
.take_payload()
.expect("Loading was successful");
let scx: &ScriptExtensions = &payload.get().data;
assert_eq!(
scx.get_script_extensions_val('𐓐' as u32).as_zerovec(), ZeroVec::<Script>::alloc_from_slice(&[Script::Osage])
);
assert_eq!(
scx.get_script_extensions_val('🥳' as u32).as_zerovec(), ZeroVec::<Script>::alloc_from_slice(&[Script::Common])
);
assert_eq!(
scx.get_script_extensions_val(0x200D).as_zerovec(), ZeroVec::<Script>::alloc_from_slice(&[Script::Inherited])
);
assert_eq!(
scx.get_script_extensions_val('௫' as u32).as_zerovec(), ZeroVec::<Script>::alloc_from_slice(&[Script::Tamil, Script::Grantha])
);
assert_eq!(
scx.get_script_extensions_val(0x11303).as_zerovec(), ZeroVec::<Script>::alloc_from_slice(&[Script::Tamil, Script::Grantha])
);
assert_eq!(
scx.get_script_extensions_val(0x30A0).as_zerovec(), ZeroVec::<Script>::alloc_from_slice(&[Script::Hiragana, Script::Katakana])
);
assert_eq!(
scx.get_script_extensions_val(0x11_0000).as_zerovec(), ZeroVec::<Script>::alloc_from_slice(&[Script::Unknown])
);
}
#[test]
fn test_has_script() {
let root_dir = icu_testdata::paths::uprops_toml_root();
let provider = ScriptExtensionsPropertyProvider::try_new(&root_dir)
.expect("TOML should load successfully");
let payload: DataPayload<ScriptExtensionsPropertyV1Marker> = provider
.load_payload(&DataRequest {
resource_path: ResourcePath {
key: key::SCRIPT_EXTENSIONS_V1,
options: ResourceOptions::default(),
},
})
.expect("The data should be valid")
.take_payload()
.expect("Loading was successful");
let scx: &ScriptExtensions = &payload.get().data;
assert!(scx.has_script('𐓐' as u32, Script::Osage));
assert!(!scx.has_script('𐓐' as u32, Script::Common));
assert!(!scx.has_script('𐓐' as u32, Script::Inherited));
assert!(scx.has_script('🥳' as u32, Script::Common));
assert!(!scx.has_script('🥳' as u32, Script::Inherited));
assert!(!scx.has_script(0x200D, Script::Common));
assert!(scx.has_script(0x200D, Script::Inherited));
assert!(scx.has_script('௫' as u32, Script::Tamil));
assert!(scx.has_script('௫' as u32, Script::Grantha));
assert!(!scx.has_script('௫' as u32, Script::Common));
assert!(!scx.has_script('௫' as u32, Script::Inherited));
assert!(scx.has_script(0x11303, Script::Tamil));
assert!(scx.has_script(0x11303, Script::Grantha));
assert!(!scx.has_script(0x11303, Script::Common));
assert!(!scx.has_script(0x11303, Script::Inherited));
assert!(scx.has_script(0x30A0, Script::Hiragana));
assert!(scx.has_script(0x30A0, Script::Katakana));
assert!(!scx.has_script(0x30A0, Script::Common));
assert!(!scx.has_script(0x30A0, Script::Inherited));
assert!(!scx.has_script(0x0964, Script::Common));
assert!(scx.has_script(0x0964, Script::Devanagari));
assert!(scx.has_script(0x0964, Script::Bengali));
assert!(!scx.has_script(0x063F, Script::Common));
assert!(scx.has_script(0x063F, Script::Arabic)); assert!(!scx.has_script(0x063F, Script::Syriac));
assert!(!scx.has_script(0x063F, Script::Thaana));
assert!(!scx.has_script(0x0640, Script::Common)); assert!(scx.has_script(0x0640, Script::Arabic));
assert!(scx.has_script(0x0640, Script::Syriac));
assert!(!scx.has_script(0x0640, Script::Thaana));
assert!(!scx.has_script(0x0650, Script::Inherited)); assert!(scx.has_script(0x0650, Script::Arabic));
assert!(scx.has_script(0x0650, Script::Syriac));
assert!(!scx.has_script(0x0650, Script::Thaana));
assert!(!scx.has_script(0x0660, Script::Common)); assert!(scx.has_script(0x0660, Script::Arabic));
assert!(!scx.has_script(0x0660, Script::Syriac));
assert!(scx.has_script(0x0660, Script::Thaana));
assert!(!scx.has_script(0xFDF2, Script::Common));
assert!(scx.has_script(0xFDF2, Script::Arabic)); assert!(!scx.has_script(0xFDF2, Script::Syriac));
assert!(scx.has_script(0xFDF2, Script::Thaana));
assert!(!scx.has_script(0x0640, Script(0xAFFE)));
}
#[test]
fn test_get_script_extensions_set() {
let root_dir = icu_testdata::paths::uprops_toml_root();
let provider = ScriptExtensionsPropertyProvider::try_new(&root_dir)
.expect("TOML should load successfully");
let payload: DataPayload<ScriptExtensionsPropertyV1Marker> = provider
.load_payload(&DataRequest {
resource_path: ResourcePath {
key: key::SCRIPT_EXTENSIONS_V1,
options: ResourceOptions::default(),
},
})
.expect("The data should be valid")
.take_payload()
.expect("Loading was successful");
let scx: &ScriptExtensions = &payload.get().data;
let grantha = scx.get_script_extensions_set(Script::Grantha);
assert!(!grantha.contains_u32(0x0BE5)); assert!(grantha.contains_u32(0x0BE6)); assert!(grantha.contains_u32(0x0BEB)); assert!(grantha.contains_u32(0x0BEF)); assert!(grantha.contains_u32(0x0BF2)); assert!(grantha.contains_u32(0x0BF3)); assert!(!grantha.contains_u32(0x0BF4)); assert!(grantha.contains_u32(0x11300)); assert!(grantha.contains_u32(0x11301)); assert!(grantha.contains_u32(0x11302)); assert!(grantha.contains_u32(0x11303)); assert!(!grantha.contains_u32(0x11304)); assert!(grantha.contains_u32(0x11305));
let tamil = scx.get_script_extensions_set(Script::Tamil);
assert!(!tamil.contains_u32(0x0BE5)); assert!(tamil.contains_u32(0x0BE6)); assert!(tamil.contains_u32(0x0BEB)); assert!(tamil.contains_u32(0x0BEF)); assert!(tamil.contains_u32(0x0BF2)); assert!(tamil.contains_u32(0x0BF3)); assert!(tamil.contains_u32(0x0BF4)); assert!(!tamil.contains_u32(0x11300)); assert!(tamil.contains_u32(0x11301)); assert!(!tamil.contains_u32(0x11302)); assert!(tamil.contains_u32(0x11303)); assert!(!tamil.contains_u32(0x11304)); assert!(!tamil.contains_u32(0x11305));
let hiragana = scx.get_script_extensions_set(Script::Hiragana);
assert!(hiragana.contains_u32(0x3046)); assert!(hiragana.contains_u32(0x309F)); assert!(hiragana.contains_u32(0x30A0)); assert!(!hiragana.contains_u32(0x30A1)); assert!(hiragana.contains_u32(0x30FB)); assert!(hiragana.contains_u32(0x30FC)); assert!(!hiragana.contains_u32(0x30FD));
let katakana = scx.get_script_extensions_set(Script::Katakana);
assert!(!katakana.contains_u32(0x3046)); assert!(!katakana.contains_u32(0x309F)); assert!(katakana.contains_u32(0x30A0)); assert!(katakana.contains_u32(0x30A1)); assert!(katakana.contains_u32(0x30FB)); assert!(katakana.contains_u32(0x30FC)); assert!(katakana.contains_u32(0x30FD));
let common = scx.get_script_extensions_set(Script::Common);
assert!(common.contains('🥳'));
assert!(!common.contains_u32(0x200D));
assert!(!common.contains_u32(0x30A0));
let inherited = scx.get_script_extensions_set(Script::Inherited);
assert!(!inherited.contains('🥳'));
assert!(inherited.contains_u32(0x200D));
assert!(!inherited.contains_u32(0x30A0));
let bengali = scx.get_script_extensions_set(Script::Bengali);
assert!(bengali.contains_u32(0x09E7)); assert!(!bengali.contains_u32(0x0963)); assert!(bengali.contains_u32(0x0964)); assert!(bengali.contains_u32(0x0965)); assert!(!bengali.contains_u32(0x0966));
let devanagari = scx.get_script_extensions_set(Script::Devanagari);
assert!(!devanagari.contains_u32(0x09E7)); assert!(devanagari.contains_u32(0x0963)); assert!(devanagari.contains_u32(0x0964)); assert!(devanagari.contains_u32(0x0965)); assert!(devanagari.contains_u32(0x0966));
assert!(!common.contains_u32(0x0964)); assert!(!common.contains_u32(0x0965)); }
}