use crate::provider::day_periods::DayPeriodRules;
use crate::size_test_macro::size_test;
use alloc::borrow::Cow;
use icu_pattern::SinglePlaceholderPattern;
use icu_provider::marker::ErasedMarker;
use icu_provider::prelude::*;
use icu_time::Hour;
#[cfg(feature = "serde")]
use potential_utf::PotentialUtf8;
use zerovec::VarZeroVec;
use zerovec::ule::vartuple::VarTupleULE;
#[cfg(feature = "serde")]
use zerovec::{VarZeroCow, VarZeroSlice, ule::tuplevar::Tuple2VarULE};
icu_provider::data_marker!(
DatetimeNamesYearBuddhistV1,
YearNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_year_length"
);
icu_provider::data_marker!(
DatetimeNamesYearChineseV1,
YearNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_year_length"
);
icu_provider::data_marker!(
DatetimeNamesYearCopticV1,
YearNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_year_length"
);
icu_provider::data_marker!(
DatetimeNamesYearDangiV1,
YearNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_year_length"
);
icu_provider::data_marker!(
DatetimeNamesYearEthiopianV1,
YearNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_year_length"
);
icu_provider::data_marker!(
DatetimeNamesYearGregorianV1,
YearNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_year_length"
);
icu_provider::data_marker!(
DatetimeNamesYearHebrewV1,
YearNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_year_length"
);
icu_provider::data_marker!(
DatetimeNamesYearIndianV1,
YearNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_year_length"
);
icu_provider::data_marker!(
DatetimeNamesYearHijriV1,
YearNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_year_length"
);
icu_provider::data_marker!(
DatetimeNamesYearJapaneseV1,
YearNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_year_length"
);
icu_provider::data_marker!(
DatetimeNamesYearPersianV1,
YearNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_year_length"
);
icu_provider::data_marker!(
DatetimeNamesYearRocV1,
YearNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_year_length"
);
icu_provider::data_marker!(
DatetimeNamesMonthBuddhistV1,
MonthNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_month_length"
);
icu_provider::data_marker!(
DatetimeNamesMonthChineseV1,
MonthNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_month_length"
);
icu_provider::data_marker!(
DatetimeNamesMonthCopticV1,
MonthNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_month_length"
);
icu_provider::data_marker!(
DatetimeNamesMonthDangiV1,
MonthNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_month_length"
);
icu_provider::data_marker!(
DatetimeNamesMonthEthiopianV1,
MonthNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_month_length"
);
icu_provider::data_marker!(
DatetimeNamesMonthGregorianV1,
MonthNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_month_length"
);
icu_provider::data_marker!(
DatetimeNamesMonthHebrewV1,
MonthNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_month_length"
);
icu_provider::data_marker!(
DatetimeNamesMonthIndianV1,
MonthNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_month_length"
);
icu_provider::data_marker!(
DatetimeNamesMonthHijriV1,
MonthNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_month_length"
);
icu_provider::data_marker!(
DatetimeNamesMonthJapaneseV1,
MonthNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_month_length"
);
icu_provider::data_marker!(
DatetimeNamesMonthPersianV1,
MonthNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_month_length"
);
icu_provider::data_marker!(
DatetimeNamesMonthRocV1,
MonthNames<'static>,
#[cfg(feature = "datagen")]
attributes_domain = "datetime_month_length"
);
icu_provider::data_marker!(
DatetimeNamesWeekdayV1,
WeekdayNames<'static>,
);
icu_provider::data_marker!(
DatetimeNamesDayperiodV1,
DayPeriodNames<'static>,
);
size_test!(YearNames, year_names_v1_size, 32);
#[doc = year_names_v1_size!()]
#[derive(Debug, PartialEq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)]
#[cfg_attr(feature = "datagen", derive(databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::names))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[yoke(prove_covariance_manually)]
pub enum YearNames<'data> {
FixedEras(#[cfg_attr(feature = "serde", serde(borrow))] VarZeroVec<'data, str>),
#[cfg(feature = "serde")]
VariableEras(#[cfg_attr(feature = "serde", serde(borrow))] YearNamesMap<'data>),
Cyclic(#[cfg_attr(feature = "serde", serde(borrow))] VarZeroVec<'data, str>),
}
#[cfg(feature = "serde")]
impl serde::Serialize for YearNames<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use alloc::vec::Vec;
#[derive(serde::Serialize)]
enum Raw<'a> {
FixedEras(&'a VarZeroVec<'a, str>),
VariableEras(&'a YearNamesMap<'a>),
Cyclic(&'a VarZeroVec<'a, str>),
}
let x: YearNamesMap;
match self {
Self::FixedEras(e) if e.len() == 7 => {
let mut kvs = [
PotentialUtf8::from_str("bce"),
PotentialUtf8::from_str("ce"),
PotentialUtf8::from_str("meiji"),
PotentialUtf8::from_str("taisho"),
PotentialUtf8::from_str("showa"),
PotentialUtf8::from_str("heisei"),
PotentialUtf8::from_str("reiwa"),
]
.into_iter()
.zip(e.iter())
.collect::<Vec<_>>();
kvs.sort_unstable();
let (ks, vs) = kvs.into_iter().unzip::<_, _, Vec<_>, Vec<_>>();
x = VarZeroCow::from_encodeable(&(ks, vs));
Raw::VariableEras(&x)
}
Self::FixedEras(e) => Raw::FixedEras(e),
Self::VariableEras(e) => Raw::VariableEras(e),
Self::Cyclic(c) => Raw::Cyclic(c),
}
.serialize(serializer)
}
}
icu_provider::data_struct!(
YearNames<'_>,
#[cfg(feature = "datagen")]
);
#[cfg(feature = "serde")]
type YearNamesMap<'data> =
VarZeroCow<'data, Tuple2VarULE<VarZeroSlice<PotentialUtf8>, VarZeroSlice<str>>>;
#[cfg(feature = "serde")]
pub(crate) fn get_year_name_from_map<'a>(
map: &'a YearNamesMap<'_>,
year: &PotentialUtf8,
) -> Option<&'a str> {
let idx = map.a().binary_search_by(|x| x.cmp(year)).ok()?;
map.b().get(idx)
}
size_test!(MonthNames, month_names_v1_size, 32);
#[doc = month_names_v1_size!()]
#[derive(Debug, PartialEq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)]
#[cfg_attr(feature = "datagen", derive(databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::names))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[yoke(prove_covariance_manually)]
pub enum MonthNames<'data> {
Linear(#[cfg_attr(feature = "serde", serde(borrow))] VarZeroVec<'data, str>),
#[cfg(feature = "serde")]
LeapLinear(#[cfg_attr(feature = "serde", serde(borrow))] VarZeroVec<'data, str>),
LeapNumeric(
#[cfg_attr(
feature = "serde",
serde(
borrow,
deserialize_with = "icu_pattern::deserialize_borrowed_cow::<icu_pattern::SinglePlaceholder, _>"
)
)]
Cow<'data, SinglePlaceholderPattern>,
),
LeapNumericWithBase(
#[cfg_attr(feature = "serde", serde(borrow))]
VarZeroVec<'data, VarTupleULE<i8, SinglePlaceholderPattern>>,
),
Numeric,
LeapPattern(VarZeroVec<'data, str>),
}
#[cfg(feature = "serde")]
impl serde::Serialize for MonthNames<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
#[derive(serde::Serialize)]
enum Raw<'a> {
Linear(&'a VarZeroVec<'a, str>),
LeapLinear(&'a VarZeroVec<'a, str>),
LeapNumeric(&'a Cow<'a, SinglePlaceholderPattern>),
LeapNumericWithBase(&'a VarZeroVec<'a, VarTupleULE<i8, SinglePlaceholderPattern>>),
Numeric,
}
let z;
match self {
Self::Numeric => Raw::Numeric,
Self::Linear(l) => Raw::Linear(l),
Self::LeapLinear(l) => Raw::LeapLinear(l),
Self::LeapNumeric(l) => Raw::LeapNumeric(l),
Self::LeapNumericWithBase(l) => Raw::LeapNumericWithBase(l),
Self::LeapPattern(l) => {
use alloc::string::String;
use alloc::vec::Vec;
use zerovec::vecs::VarZeroVecOwned;
let leap_pattern = l.get(l.len() - 2).unwrap_or_default();
let leap_base_pattern = l.get(l.len() - 1).unwrap_or_default();
let normal_names = l.iter().take(l.len() - 2);
let r = if leap_pattern.starts_with('\0') {
normal_names
.map(String::from)
.chain([
String::new(),
String::new(),
String::new(),
String::new(),
SinglePlaceholderPattern::from_ref_store(leap_pattern)
.unwrap_or(SinglePlaceholderPattern::PASS_THROUGH)
.interpolate_to_string([l.get(5).unwrap_or_default()]),
SinglePlaceholderPattern::from_ref_store(leap_base_pattern)
.unwrap_or(SinglePlaceholderPattern::PASS_THROUGH)
.interpolate_to_string([l.get(5).unwrap_or_default()]),
String::new(),
String::new(),
String::new(),
String::new(),
String::new(),
String::new(),
])
.collect()
} else {
normal_names
.clone()
.map(String::from)
.chain(normal_names.map(|m| {
SinglePlaceholderPattern::from_ref_store(leap_pattern)
.unwrap_or(SinglePlaceholderPattern::PASS_THROUGH)
.interpolate_to_string([m])
}))
.collect::<Vec<_>>()
};
#[allow(clippy::unwrap_used)] {
z = VarZeroVecOwned::try_from_elements(&r).unwrap().into();
}
Raw::LeapLinear(&z)
}
}
.serialize(serializer)
}
}
icu_provider::data_struct!(
MonthNames<'_>,
#[cfg(feature = "datagen")]
);
size_test!(WeekdayNames, linear_names_v1_size, 24);
#[doc = linear_names_v1_size!()]
#[derive(Debug, PartialEq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)]
#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::names))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[yoke(prove_covariance_manually)]
pub struct WeekdayNames<'data> {
#[cfg_attr(feature = "serde", serde(borrow))]
pub names: VarZeroVec<'data, str>,
}
icu_provider::data_struct!(
WeekdayNames<'_>,
#[cfg(feature = "datagen")]
);
impl WeekdayNames<'_> {
#[cfg(feature = "datagen")]
pub fn new<'a>(names: impl Iterator<Item = (icu_calendar::types::Weekday, &'a str)>) -> Self {
let mut v = [""; 7];
for (day, name) in names {
use icu_calendar::types::Weekday::*;
*match day {
Sunday => &mut v[0],
Monday => &mut v[1],
Tuesday => &mut v[2],
Wednesday => &mut v[3],
Thursday => &mut v[4],
Friday => &mut v[5],
Saturday => &mut v[6],
} = name;
}
Self { names: (&v).into() }
}
pub fn get(&self, day: icu_calendar::types::Weekday) -> Option<&str> {
use icu_calendar::types::Weekday::*;
self.names.get(match day {
Sunday => 0,
Monday => 1,
Tuesday => 2,
Wednesday => 3,
Thursday => 4,
Friday => 5,
Saturday => 6,
})
}
}
size_test!(DayPeriodNames, day_period_names_v1_size, 24);
#[doc = day_period_names_v1_size!()]
#[derive(Debug, PartialEq, Clone, yoke::Yokeable, zerofrom::ZeroFrom)]
#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))]
#[cfg_attr(feature = "datagen", databake(path = icu_datetime::provider::names))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[yoke(prove_covariance_manually)]
pub struct DayPeriodNames<'data> {
#[cfg_attr(feature = "serde", serde(borrow))]
pub names: VarZeroVec<'data, str>,
}
icu_provider::data_struct!(
DayPeriodNames<'_>,
#[cfg(feature = "datagen")]
);
impl DayPeriodNames<'_> {
pub(crate) fn am(&self) -> Option<&str> {
self.names.get(0)
}
pub(crate) fn pm(&self) -> Option<&str> {
self.names.get(1)
}
pub(crate) fn noon(&self) -> Option<&str> {
self.names.get(2).filter(|s| !s.is_empty())
}
pub(crate) fn midnight(&self) -> Option<&str> {
self.names.get(3).filter(|s| !s.is_empty())
}
pub(crate) fn flexible_day_period(&self, hour: Hour) -> Option<&str> {
let (rules, first_name) = self.names.get(4)?.split_at_checked(4)?;
let offset = DayPeriodRules::decode_from_str(rules)?.name_offset(hour);
if offset == 0 {
Some(first_name)
} else {
self.names.get(4 + offset)
}
}
pub fn day_period_rules(&self) -> Option<DayPeriodRules> {
let (rules, _) = self.names.get(4)?.split_at_checked(4)?;
DayPeriodRules::decode_from_str(rules)
}
}
pub type YearNamesV1 = ErasedMarker<YearNames<'static>>;
pub type MonthNamesV1 = ErasedMarker<MonthNames<'static>>;
pub use DatetimeNamesWeekdayV1 as WeekdayNamesV1;
pub use DatetimeNamesDayperiodV1 as DayPeriodNamesV1;
#[test]
fn test_dayperiod_names() {
let names_zh = DataProvider::<DayPeriodNamesV1>::load(
&crate::provider::Baked,
DataRequest {
id: DataIdentifierBorrowed::for_marker_attributes_and_locale(
DataMarkerAttributes::from_str_or_panic("5"),
&icu::locale::data_locale!("zh"),
),
..Default::default()
},
)
.unwrap()
.payload;
assert_eq!(names_zh.get().am(), Some("上午"));
assert_eq!(names_zh.get().pm(), Some("下午"));
assert_eq!(
names_zh.get().flexible_day_period(12u8.try_into().unwrap()),
None
);
let names_zh_hant = DataProvider::<DayPeriodNamesV1>::load(
&crate::provider::Baked,
DataRequest {
id: DataIdentifierBorrowed::for_marker_attributes_and_locale(
DataMarkerAttributes::from_str_or_panic("5"),
&icu::locale::data_locale!("zh-Hant"),
),
..Default::default()
},
)
.unwrap()
.payload;
assert_eq!(names_zh_hant.get().am(), Some("上午"));
assert_eq!(names_zh_hant.get().pm(), Some("下午"));
assert_eq!(
names_zh_hant
.get()
.flexible_day_period(19u8.try_into().unwrap()),
Some("晚上")
);
}