#[cfg(feature = "alloc")]
use crate::code_point_set::CodePointSetData;
use crate::props::GeneralCategory;
use crate::props::GeneralCategoryGroup;
use crate::provider::*;
use core::ops::RangeInclusive;
use icu_collections::codepointtrie::{CodePointMapRange, CodePointTrie, TrieValue};
use icu_provider::marker::ErasedMarker;
use icu_provider::prelude::*;
#[derive(Debug, Clone)]
pub struct CodePointMapData<T: TrieValue> {
data: DataPayload<ErasedMarker<PropertyCodePointMap<'static, T>>>,
}
impl<T: TrieValue> CodePointMapData<T> {
#[cfg(feature = "compiled_data")]
#[expect(clippy::new_ret_no_self)]
pub const fn new() -> CodePointMapDataBorrowed<'static, T>
where
T: EnumeratedProperty,
{
CodePointMapDataBorrowed::new()
}
#[cfg(feature = "serde")]
#[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER, Self::new)]
pub fn try_new_with_buffer_provider(
provider: &(impl BufferProvider + ?Sized),
) -> Result<Self, DataError>
where
T: EnumeratedProperty + for<'a> serde::Deserialize<'a>,
{
use icu_provider::buf::AsDeserializingBufferProvider;
Self::try_new_unstable(&provider.as_deserializing())
}
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new)]
pub fn try_new_unstable(
provider: &(impl DataProvider<T::DataMarker> + ?Sized),
) -> Result<Self, DataError>
where
T: EnumeratedProperty,
{
Ok(Self {
data: provider.load(Default::default())?.payload.cast(),
})
}
#[inline]
pub fn as_borrowed(&self) -> CodePointMapDataBorrowed<'_, T> {
CodePointMapDataBorrowed {
map: self.data.get(),
}
}
#[cfg(feature = "alloc")]
pub fn try_into_converted<P>(self) -> Result<CodePointMapData<P>, zerovec::ule::UleError>
where
P: TrieValue,
{
self.data
.try_map_project(|data, _| data.try_into_converted())
.map(CodePointMapData::from_data::<ErasedMarker<PropertyCodePointMap<'static, P>>>)
}
pub(crate) fn from_data<M>(data: DataPayload<M>) -> Self
where
M: DynamicDataMarker<DataStruct = PropertyCodePointMap<'static, T>>,
{
Self { data: data.cast() }
}
pub fn from_code_point_trie(trie: CodePointTrie<'static, T>) -> Self {
let set = PropertyCodePointMap::from_code_point_trie(trie);
CodePointMapData::from_data(
DataPayload::<ErasedMarker<PropertyCodePointMap<'static, 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 PropertyCodePointMap<'a, T>,
}
impl<'a, T: TrieValue> CodePointMapDataBorrowed<'a, T> {
#[inline]
pub fn get(self, ch: char) -> T {
self.map.get(ch)
}
#[inline]
pub fn get32(self, ch: u32) -> T {
self.map.get32(ch)
}
#[cfg(feature = "alloc")]
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 CodePointMapDataBorrowed<'_, GeneralCategory> {
#[cfg(feature = "alloc")]
pub fn get_set_for_value_group(self, value: GeneralCategoryGroup) -> CodePointSetData {
let matching_gc_ranges = self
.iter_ranges()
.filter(|cpm_range| (1 << cpm_range.value as u32) & value.0 != 0)
.map(|cpm_range| cpm_range.range);
CodePointSetData::from_code_point_inversion_list(matching_gc_ranges.collect())
}
}
#[cfg(feature = "compiled_data")]
impl<T: EnumeratedProperty> Default for CodePointMapDataBorrowed<'static, T> {
fn default() -> Self {
Self::new()
}
}
impl<T: TrieValue> CodePointMapDataBorrowed<'static, T> {
#[cfg(feature = "compiled_data")]
pub const fn new() -> Self
where
T: EnumeratedProperty,
{
CodePointMapDataBorrowed { map: T::SINGLETON }
}
pub const fn static_to_owned(self) -> CodePointMapData<T> {
CodePointMapData {
data: DataPayload::from_static_ref(self.map),
}
}
}
impl<'a> CodePointMapDataBorrowed<'a, GeneralCategory> {
pub fn iter_ranges_for_group(
self,
group: 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)
}
}
pub trait EnumeratedProperty: crate::private::Sealed + TrieValue {
#[doc(hidden)]
type DataMarker: DataMarker<DataStruct = PropertyCodePointMap<'static, Self>>;
#[doc(hidden)]
#[cfg(feature = "compiled_data")]
const SINGLETON: &'static PropertyCodePointMap<'static, Self>;
const NAME: &'static [u8];
const SHORT_NAME: &'static [u8];
#[cfg(feature = "compiled_data")]
fn for_char(ch: char) -> Self {
CodePointMapData::new().get(ch)
}
}