use crate::provider::*;
use crate::LocaleExpander;
use icu_locale_core::subtags::Script;
use icu_locale_core::LanguageIdentifier;
use icu_provider::prelude::*;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[non_exhaustive]
pub enum Direction {
LeftToRight,
RightToLeft,
}
#[derive(Debug)]
pub struct LocaleDirectionality<Expander = LocaleExpander> {
script_direction: DataPayload<LocaleScriptDirectionV1>,
expander: Expander,
}
impl LocaleDirectionality<LocaleExpander> {
#[cfg(feature = "compiled_data")]
pub const fn new_common() -> Self {
Self::new_with_expander(LocaleExpander::new_common())
}
#[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER, Self::new_common)]
#[cfg(feature = "serde")]
pub fn try_new_common_with_buffer_provider(
provider: &(impl BufferProvider + ?Sized),
) -> Result<Self, DataError> {
let expander = LocaleExpander::try_new_common_with_buffer_provider(provider)?;
Self::try_new_with_expander_unstable(&provider.as_deserializing(), expander)
}
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_common)]
pub fn try_new_common_unstable<P>(provider: &P) -> Result<LocaleDirectionality, DataError>
where
P: DataProvider<LocaleScriptDirectionV1>
+ DataProvider<LocaleLikelySubtagsLanguageV1>
+ DataProvider<LocaleLikelySubtagsScriptRegionV1>
+ ?Sized,
{
let expander = LocaleExpander::try_new_common_unstable(provider)?;
Self::try_new_with_expander_unstable(provider, expander)
}
#[cfg(feature = "compiled_data")]
pub const fn new_extended() -> Self {
Self::new_with_expander(LocaleExpander::new_extended())
}
#[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER, Self::new_extended)]
#[cfg(feature = "serde")]
pub fn try_new_extended_with_buffer_provider(
provider: &(impl BufferProvider + ?Sized),
) -> Result<Self, DataError> {
let expander = LocaleExpander::try_new_extended_with_buffer_provider(provider)?;
Self::try_new_with_expander_unstable(&provider.as_deserializing(), expander)
}
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_extended)]
pub fn try_new_extended_unstable<P>(provider: &P) -> Result<LocaleDirectionality, DataError>
where
P: DataProvider<LocaleScriptDirectionV1>
+ DataProvider<LocaleLikelySubtagsLanguageV1>
+ DataProvider<LocaleLikelySubtagsScriptRegionV1>
+ DataProvider<LocaleLikelySubtagsExtendedV1>
+ ?Sized,
{
let expander = LocaleExpander::try_new_extended_unstable(provider)?;
Self::try_new_with_expander_unstable(provider, expander)
}
}
impl<Expander: AsRef<LocaleExpander>> LocaleDirectionality<Expander> {
#[cfg(feature = "compiled_data")]
pub const fn new_with_expander(expander: Expander) -> Self {
LocaleDirectionality {
script_direction: DataPayload::from_static_ref(
crate::provider::Baked::SINGLETON_LOCALE_SCRIPT_DIRECTION_V1,
),
expander,
}
}
#[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_with_expander)]
pub fn try_new_with_expander_unstable<P>(
provider: &P,
expander: Expander,
) -> Result<Self, DataError>
where
P: DataProvider<LocaleScriptDirectionV1> + ?Sized,
{
let script_direction = provider.load(Default::default())?.payload;
Ok(LocaleDirectionality {
script_direction,
expander,
})
}
pub fn get(&self, langid: &LanguageIdentifier) -> Option<Direction> {
let script = self.expander.as_ref().get_likely_script(langid)?;
if self.script_in_ltr(script) {
Some(Direction::LeftToRight)
} else if self.script_in_rtl(script) {
Some(Direction::RightToLeft)
} else {
None
}
}
pub fn is_right_to_left(&self, langid: &LanguageIdentifier) -> bool {
self.expander
.as_ref()
.get_likely_script(langid)
.map(|s| self.script_in_rtl(s))
.unwrap_or(false)
}
pub fn is_left_to_right(&self, langid: &LanguageIdentifier) -> bool {
self.expander
.as_ref()
.get_likely_script(langid)
.map(|s| self.script_in_ltr(s))
.unwrap_or(false)
}
fn script_in_rtl(&self, script: Script) -> bool {
self.script_direction
.get()
.rtl
.binary_search(&script.to_tinystr().to_unvalidated())
.is_ok()
}
fn script_in_ltr(&self, script: Script) -> bool {
self.script_direction
.get()
.ltr
.binary_search(&script.to_tinystr().to_unvalidated())
.is_ok()
}
}