use crate::error::PropertiesError;
use crate::provider::*;
use crate::sets::CodePointSetData;
#[cfg(doc)]
use crate::*;
use core::marker::PhantomData;
use core::ops::RangeInclusive;
use icu_collections::codepointtrie::{CodePointMapRange, CodePointTrie, TrieValue};
use icu_provider::prelude::*;
use zerovec::ZeroVecError;
#[derive(Debug, Clone)]
pub struct CodePointMapData<T: TrieValue> {
data: DataPayload<ErasedMaplikeMarker<T>>,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
struct ErasedMaplikeMarker<T>(PhantomData<T>);
impl<T: TrieValue> DataMarker for ErasedMaplikeMarker<T> {
type Yokeable = PropertyCodePointMapV1<'static, T>;
}
impl<T: TrieValue> CodePointMapData<T> {
#[inline]
pub fn as_borrowed(&self) -> CodePointMapDataBorrowed<'_, T> {
CodePointMapDataBorrowed {
map: self.data.get(),
}
}
pub fn try_into_converted<P>(self) -> Result<CodePointMapData<P>, ZeroVecError>
where
P: TrieValue,
{
self.data
.try_map_project::<ErasedMaplikeMarker<P>, _, _>(move |data, _| {
data.try_into_converted()
})
.map(CodePointMapData::from_data)
}
pub fn from_data<M>(data: DataPayload<M>) -> Self
where
M: DataMarker<Yokeable = PropertyCodePointMapV1<'static, T>>,
{
Self { data: data.cast() }
}
pub fn from_code_point_trie(trie: CodePointTrie<'static, T>) -> Self {
let set = PropertyCodePointMapV1::from_code_point_trie(trie);
CodePointMapData::from_data(DataPayload::<ErasedMaplikeMarker<T>>::from_owned(set))
}
pub fn as_code_point_trie(&self) -> Option<&CodePointTrie<'_, T>> {
self.data.get().as_code_point_trie()
}
pub fn to_code_point_trie(&self) -> CodePointTrie<'_, T> {
self.data.get().to_code_point_trie()
}
}
#[derive(Clone, Copy, Debug)]
pub struct CodePointMapDataBorrowed<'a, T: TrieValue> {
map: &'a PropertyCodePointMapV1<'a, T>,
}
impl<'a, T: TrieValue> CodePointMapDataBorrowed<'a, T> {
pub fn get(self, ch: char) -> T {
self.map.get32(ch as u32)
}
pub fn get32(self, ch: u32) -> T {
self.map.get32(ch)
}
pub fn get_set_for_value(self, value: T) -> CodePointSetData {
let set = self.map.get_set_for_value(value);
CodePointSetData::from_code_point_inversion_list(set)
}
pub fn iter_ranges(self) -> impl Iterator<Item = CodePointMapRange<T>> + 'a {
self.map.iter_ranges()
}
pub fn iter_ranges_for_value(self, val: T) -> impl Iterator<Item = RangeInclusive<u32>> + 'a {
self.map
.iter_ranges()
.filter(move |r| r.value == val)
.map(|r| r.range)
}
pub fn iter_ranges_for_value_complemented(
self,
val: T,
) -> impl Iterator<Item = RangeInclusive<u32>> + 'a {
self.map
.iter_ranges_mapped(move |value| value != val)
.filter(|v| v.value)
.map(|v| v.range)
}
#[doc(hidden)]
pub fn iter_ranges_mapped<U: Eq + 'a>(
self,
predicate: impl FnMut(T) -> U + Copy + 'a,
) -> impl Iterator<Item = CodePointMapRange<U>> + 'a {
self.map.iter_ranges_mapped(predicate)
}
}
impl<T: TrieValue> CodePointMapDataBorrowed<'static, T> {
pub const fn static_to_owned(self) -> CodePointMapData<T> {
CodePointMapData {
data: DataPayload::from_static_ref(self.map),
}
}
}
impl<'a> CodePointMapDataBorrowed<'a, crate::GeneralCategory> {
pub fn iter_ranges_for_group(
self,
group: crate::GeneralCategoryGroup,
) -> impl Iterator<Item = RangeInclusive<u32>> + 'a {
self.map
.iter_ranges_mapped(move |value| group.contains(value))
.filter(|v| v.value)
.map(|v| v.range)
}
}
macro_rules! make_map_property {
(
// currently unused
property: $prop_name:expr;
// currently unused
marker: $marker_name:ident;
value: $value_ty:path;
keyed_data_marker: $keyed_data_marker:ty;
func:
$(#[$doc:meta])*
$vis2:vis const $constname:ident => $singleton:ident;
$vis:vis fn $name:ident();
) => {
#[doc = concat!("A version of [`", stringify!($constname), "()`] that uses custom data provided by a [`DataProvider`].")]
$vis fn $name(
provider: &(impl DataProvider<$keyed_data_marker> + ?Sized)
) -> Result<CodePointMapData<$value_ty>, PropertiesError> {
Ok(provider.load(Default::default()).and_then(DataResponse::take_payload).map(CodePointMapData::from_data)?)
}
$(#[$doc])*
#[cfg(feature = "compiled_data")]
pub const fn $constname() -> CodePointMapDataBorrowed<'static, $value_ty> {
CodePointMapDataBorrowed {
map: crate::provider::Baked::$singleton
}
}
};
}
make_map_property! {
property: "General_Category";
marker: GeneralCategoryProperty;
value: crate::GeneralCategory;
keyed_data_marker: GeneralCategoryV1Marker;
func:
pub const general_category => SINGLETON_PROPS_GC_V1;
pub fn load_general_category();
}
make_map_property! {
property: "Bidi_Class";
marker: BidiClassProperty;
value: crate::BidiClass;
keyed_data_marker: BidiClassV1Marker;
func:
pub const bidi_class => SINGLETON_PROPS_BC_V1;
pub fn load_bidi_class();
}
make_map_property! {
property: "Script";
marker: ScriptProperty;
value: crate::Script;
keyed_data_marker: ScriptV1Marker;
func:
pub const script => SINGLETON_PROPS_SC_V1;
pub fn load_script();
}
make_map_property! {
property: "East_Asian_Width";
marker: EastAsianWidthProperty;
value: crate::EastAsianWidth;
keyed_data_marker: EastAsianWidthV1Marker;
func:
pub const east_asian_width => SINGLETON_PROPS_EA_V1;
pub fn load_east_asian_width();
}
make_map_property! {
property: "Line_Break";
marker: LineBreakProperty;
value: crate::LineBreak;
keyed_data_marker: LineBreakV1Marker;
func:
pub const line_break => SINGLETON_PROPS_LB_V1;
pub fn load_line_break();
}
make_map_property! {
property: "Grapheme_Cluster_Break";
marker: GraphemeClusterBreakProperty;
value: crate::GraphemeClusterBreak;
keyed_data_marker: GraphemeClusterBreakV1Marker;
func:
pub const grapheme_cluster_break => SINGLETON_PROPS_GCB_V1;
pub fn load_grapheme_cluster_break();
}
make_map_property! {
property: "Word_Break";
marker: WordBreakProperty;
value: crate::WordBreak;
keyed_data_marker: WordBreakV1Marker;
func:
pub const word_break => SINGLETON_PROPS_WB_V1;
pub fn load_word_break();
}
make_map_property! {
property: "Sentence_Break";
marker: SentenceBreakProperty;
value: crate::SentenceBreak;
keyed_data_marker: SentenceBreakV1Marker;
func:
pub const sentence_break => SINGLETON_PROPS_SB_V1;
pub fn load_sentence_break();
}
make_map_property! {
property: "Canonical_Combining_Class";
marker: CanonicalCombiningClassProperty;
value: crate::CanonicalCombiningClass;
keyed_data_marker: CanonicalCombiningClassV1Marker;
func:
pub const canonical_combining_class => SINGLETON_PROPS_CCC_V1;
pub fn load_canonical_combining_class();
}
make_map_property! {
property: "Indic_Syllabic_Category";
marker: IndicSyllabicCategoryProperty;
value: crate::IndicSyllabicCategory;
keyed_data_marker: IndicSyllabicCategoryV1Marker;
func:
pub const indic_syllabic_category => SINGLETON_PROPS_INSC_V1;
pub fn load_indic_syllabic_category();
}
make_map_property! {
property: "Joining_Type";
marker: JoiningTypeProperty;
value: crate::JoiningType;
keyed_data_marker: JoiningTypeV1Marker;
func:
pub const joining_type => SINGLETON_PROPS_JT_V1;
pub fn load_joining_type();
}