use crate::buddhist::Buddhist;
use crate::coptic::Coptic;
use crate::ethiopian::{Ethiopian, EthiopianEraStyle};
use crate::gregorian::Gregorian;
use crate::indian::Indian;
use crate::iso::Iso;
use crate::japanese::{Japanese, JapaneseExtended};
use crate::{
types, AsCalendar, Calendar, CalendarError, Date, DateDuration, DateDurationUnit, DateTime, Ref,
};
use icu_locid::{
extensions::unicode::Value, extensions_unicode_key as key, extensions_unicode_value as value,
subtags_language as language, Locale,
};
use icu_provider::prelude::*;
use core::fmt;
#[derive(Debug)]
#[non_exhaustive]
pub enum AnyCalendar {
Gregorian(Gregorian),
Buddhist(Buddhist),
Japanese(Japanese),
JapaneseExtended(JapaneseExtended),
Ethiopian(Ethiopian),
Indian(Indian),
Coptic(Coptic),
Iso(Iso),
}
#[derive(Clone, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub enum AnyDateInner {
Gregorian(<Gregorian as Calendar>::DateInner),
Buddhist(<Buddhist as Calendar>::DateInner),
Japanese(<Japanese as Calendar>::DateInner),
JapaneseExtended(<JapaneseExtended as Calendar>::DateInner),
Ethiopian(<Ethiopian as Calendar>::DateInner),
Indian(<Indian as Calendar>::DateInner),
Coptic(<Coptic as Calendar>::DateInner),
Iso(<Iso as Calendar>::DateInner),
}
macro_rules! match_cal_and_date {
(match ($cal:ident, $date:ident): ($cal_matched:ident, $date_matched:ident) => $e:expr) => {
match ($cal, $date) {
(&Self::Gregorian(ref $cal_matched), &AnyDateInner::Gregorian(ref $date_matched)) => $e,
(&Self::Buddhist(ref $cal_matched), &AnyDateInner::Buddhist(ref $date_matched)) => $e,
(&Self::Japanese(ref $cal_matched), &AnyDateInner::Japanese(ref $date_matched)) => $e,
(
&Self::JapaneseExtended(ref $cal_matched),
&AnyDateInner::JapaneseExtended(ref $date_matched),
) => $e,
(&Self::Ethiopian(ref $cal_matched), &AnyDateInner::Ethiopian(ref $date_matched)) => $e,
(&Self::Indian(ref $cal_matched), &AnyDateInner::Indian(ref $date_matched)) => $e,
(&Self::Coptic(ref $cal_matched), &AnyDateInner::Coptic(ref $date_matched)) => $e,
(&Self::Iso(ref $cal_matched), &AnyDateInner::Iso(ref $date_matched)) => $e,
_ => panic!(
"Found AnyCalendar with mixed calendar type {} and date type {}!",
$cal.calendar_name(),
$date.calendar_name()
),
}
};
}
impl Calendar for AnyCalendar {
type DateInner = AnyDateInner;
fn date_from_codes(
&self,
era: types::Era,
year: i32,
month_code: types::MonthCode,
day: u8,
) -> Result<Self::DateInner, CalendarError> {
let ret = match *self {
Self::Gregorian(ref c) => {
AnyDateInner::Gregorian(c.date_from_codes(era, year, month_code, day)?)
}
Self::Buddhist(ref c) => {
AnyDateInner::Buddhist(c.date_from_codes(era, year, month_code, day)?)
}
Self::Japanese(ref c) => {
AnyDateInner::Japanese(c.date_from_codes(era, year, month_code, day)?)
}
Self::JapaneseExtended(ref c) => {
AnyDateInner::JapaneseExtended(c.date_from_codes(era, year, month_code, day)?)
}
Self::Ethiopian(ref c) => {
AnyDateInner::Ethiopian(c.date_from_codes(era, year, month_code, day)?)
}
Self::Indian(ref c) => {
AnyDateInner::Indian(c.date_from_codes(era, year, month_code, day)?)
}
Self::Coptic(ref c) => {
AnyDateInner::Coptic(c.date_from_codes(era, year, month_code, day)?)
}
Self::Iso(ref c) => AnyDateInner::Iso(c.date_from_codes(era, year, month_code, day)?),
};
Ok(ret)
}
fn date_from_iso(&self, iso: Date<Iso>) -> AnyDateInner {
match *self {
Self::Gregorian(ref c) => AnyDateInner::Gregorian(c.date_from_iso(iso)),
Self::Buddhist(ref c) => AnyDateInner::Buddhist(c.date_from_iso(iso)),
Self::Japanese(ref c) => AnyDateInner::Japanese(c.date_from_iso(iso)),
Self::JapaneseExtended(ref c) => AnyDateInner::JapaneseExtended(c.date_from_iso(iso)),
Self::Ethiopian(ref c) => AnyDateInner::Ethiopian(c.date_from_iso(iso)),
Self::Indian(ref c) => AnyDateInner::Indian(c.date_from_iso(iso)),
Self::Coptic(ref c) => AnyDateInner::Coptic(c.date_from_iso(iso)),
Self::Iso(ref c) => AnyDateInner::Iso(c.date_from_iso(iso)),
}
}
fn date_to_iso(&self, date: &Self::DateInner) -> Date<Iso> {
match_cal_and_date!(match (self, date): (c, d) => c.date_to_iso(d))
}
fn months_in_year(&self, date: &Self::DateInner) -> u8 {
match_cal_and_date!(match (self, date): (c, d) => c.months_in_year(d))
}
fn days_in_year(&self, date: &Self::DateInner) -> u32 {
match_cal_and_date!(match (self, date): (c, d) => c.days_in_year(d))
}
fn days_in_month(&self, date: &Self::DateInner) -> u8 {
match_cal_and_date!(match (self, date): (c, d) => c.days_in_month(d))
}
fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) {
match (self, date) {
(Self::Gregorian(c), &mut AnyDateInner::Gregorian(ref mut d)) => {
c.offset_date(d, offset.cast_unit())
}
(Self::Buddhist(c), &mut AnyDateInner::Buddhist(ref mut d)) => {
c.offset_date(d, offset.cast_unit())
}
(Self::Japanese(c), &mut AnyDateInner::Japanese(ref mut d)) => {
c.offset_date(d, offset.cast_unit())
}
(Self::JapaneseExtended(c), &mut AnyDateInner::JapaneseExtended(ref mut d)) => {
c.offset_date(d, offset.cast_unit())
}
(Self::Ethiopian(c), &mut AnyDateInner::Ethiopian(ref mut d)) => {
c.offset_date(d, offset.cast_unit())
}
(Self::Indian(c), &mut AnyDateInner::Indian(ref mut d)) => {
c.offset_date(d, offset.cast_unit())
}
(Self::Coptic(c), &mut AnyDateInner::Coptic(ref mut d)) => {
c.offset_date(d, offset.cast_unit())
}
(Self::Iso(c), &mut AnyDateInner::Iso(ref mut d)) => {
c.offset_date(d, offset.cast_unit())
}
#[allow(clippy::panic)]
(_, d) => panic!(
"Found AnyCalendar with mixed calendar type {} and date type {}!",
self.calendar_name(),
d.calendar_name()
),
}
}
fn until(
&self,
date1: &Self::DateInner,
date2: &Self::DateInner,
calendar2: &Self,
largest_unit: DateDurationUnit,
smallest_unit: DateDurationUnit,
) -> DateDuration<Self> {
match (self, calendar2, date1, date2) {
(
Self::Gregorian(c1),
Self::Gregorian(c2),
AnyDateInner::Gregorian(d1),
AnyDateInner::Gregorian(d2),
) => c1
.until(d1, d2, c2, largest_unit, smallest_unit)
.cast_unit(),
(
Self::Buddhist(c1),
Self::Buddhist(c2),
AnyDateInner::Buddhist(d1),
AnyDateInner::Buddhist(d2),
) => c1
.until(d1, d2, c2, largest_unit, smallest_unit)
.cast_unit(),
(
Self::Japanese(c1),
Self::Japanese(c2),
AnyDateInner::Japanese(d1),
AnyDateInner::Japanese(d2),
) => c1
.until(d1, d2, c2, largest_unit, smallest_unit)
.cast_unit(),
(
Self::JapaneseExtended(c1),
Self::JapaneseExtended(c2),
AnyDateInner::JapaneseExtended(d1),
AnyDateInner::JapaneseExtended(d2),
) => c1
.until(d1, d2, c2, largest_unit, smallest_unit)
.cast_unit(),
(
Self::Ethiopian(c1),
Self::Ethiopian(c2),
AnyDateInner::Ethiopian(d1),
AnyDateInner::Ethiopian(d2),
) => c1
.until(d1, d2, c2, largest_unit, smallest_unit)
.cast_unit(),
(
Self::Indian(c1),
Self::Indian(c2),
AnyDateInner::Indian(d1),
AnyDateInner::Indian(d2),
) => c1
.until(d1, d2, c2, largest_unit, smallest_unit)
.cast_unit(),
(
Self::Coptic(c1),
Self::Coptic(c2),
AnyDateInner::Coptic(d1),
AnyDateInner::Coptic(d2),
) => c1
.until(d1, d2, c2, largest_unit, smallest_unit)
.cast_unit(),
(Self::Iso(c1), Self::Iso(c2), AnyDateInner::Iso(d1), AnyDateInner::Iso(d2)) => c1
.until(d1, d2, c2, largest_unit, smallest_unit)
.cast_unit(),
_ => {
let iso = calendar2.date_to_iso(date2);
match_cal_and_date!(match (self, date1):
(c1, d1) => {
let d2 = c1.date_from_iso(iso);
let until = c1.until(d1, &d2, c1, largest_unit, smallest_unit);
until.cast_unit::<AnyCalendar>()
}
)
}
}
}
fn year(&self, date: &Self::DateInner) -> types::FormattableYear {
match_cal_and_date!(match (self, date): (c, d) => c.year(d))
}
fn month(&self, date: &Self::DateInner) -> types::FormattableMonth {
match_cal_and_date!(match (self, date): (c, d) => c.month(d))
}
fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
match_cal_and_date!(match (self, date): (c, d) => c.day_of_month(d))
}
fn day_of_year_info(&self, date: &Self::DateInner) -> types::DayOfYearInfo {
match_cal_and_date!(match (self, date): (c, d) => c.day_of_year_info(d))
}
fn debug_name(&self) -> &'static str {
match *self {
Self::Gregorian(_) => "AnyCalendar (Gregorian)",
Self::Buddhist(_) => "AnyCalendar (Buddhist)",
Self::Japanese(_) => "AnyCalendar (Japanese)",
Self::JapaneseExtended(_) => "AnyCalendar (Japanese, Historical Era Data)",
Self::Ethiopian(_) => "AnyCalendar (Ethiopian)",
Self::Indian(_) => "AnyCalendar (Indian)",
Self::Coptic(_) => "AnyCalendar (Coptic)",
Self::Iso(_) => "AnyCalendar (Iso)",
}
}
fn any_calendar_kind(&self) -> Option<AnyCalendarKind> {
Some(self.kind())
}
}
impl AnyCalendar {
pub fn try_new_with_any_provider<P>(
provider: &P,
kind: AnyCalendarKind,
) -> Result<Self, CalendarError>
where
P: AnyProvider + ?Sized,
{
Ok(match kind {
AnyCalendarKind::Gregorian => AnyCalendar::Gregorian(Gregorian),
AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist),
AnyCalendarKind::Japanese => {
AnyCalendar::Japanese(Japanese::try_new_with_any_provider(provider)?)
}
AnyCalendarKind::JapaneseExtended => AnyCalendar::JapaneseExtended(
JapaneseExtended::try_new_with_any_provider(provider)?,
),
AnyCalendarKind::Indian => AnyCalendar::Indian(Indian),
AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic),
AnyCalendarKind::Iso => AnyCalendar::Iso(Iso),
AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style(
EthiopianEraStyle::AmeteMihret,
)),
AnyCalendarKind::EthiopianAmeteAlem => {
AnyCalendar::Ethiopian(Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteAlem))
}
})
}
#[cfg(feature = "serde")]
pub fn try_new_with_buffer_provider<P>(
provider: &P,
kind: AnyCalendarKind,
) -> Result<Self, CalendarError>
where
P: BufferProvider + ?Sized,
{
Ok(match kind {
AnyCalendarKind::Gregorian => AnyCalendar::Gregorian(Gregorian),
AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist),
AnyCalendarKind::Japanese => {
AnyCalendar::Japanese(Japanese::try_new_with_buffer_provider(provider)?)
}
AnyCalendarKind::JapaneseExtended => AnyCalendar::JapaneseExtended(
JapaneseExtended::try_new_with_buffer_provider(provider)?,
),
AnyCalendarKind::Indian => AnyCalendar::Indian(Indian),
AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic),
AnyCalendarKind::Iso => AnyCalendar::Iso(Iso),
AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style(
EthiopianEraStyle::AmeteMihret,
)),
AnyCalendarKind::EthiopianAmeteAlem => {
AnyCalendar::Ethiopian(Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteAlem))
}
})
}
pub fn try_new_unstable<P>(provider: &P, kind: AnyCalendarKind) -> Result<Self, CalendarError>
where
P: DataProvider<crate::provider::JapaneseErasV1Marker>
+ DataProvider<crate::provider::JapaneseExtendedErasV1Marker>
+ ?Sized,
{
Ok(match kind {
AnyCalendarKind::Gregorian => AnyCalendar::Gregorian(Gregorian),
AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist),
AnyCalendarKind::Japanese => {
AnyCalendar::Japanese(Japanese::try_new_unstable(provider)?)
}
AnyCalendarKind::JapaneseExtended => {
AnyCalendar::JapaneseExtended(JapaneseExtended::try_new_unstable(provider)?)
}
AnyCalendarKind::Indian => AnyCalendar::Indian(Indian),
AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic),
AnyCalendarKind::Iso => AnyCalendar::Iso(Iso),
AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style(
EthiopianEraStyle::AmeteMihret,
)),
AnyCalendarKind::EthiopianAmeteAlem => {
AnyCalendar::Ethiopian(Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteAlem))
}
})
}
icu_provider::gen_any_buffer_constructors!(
locale: include,
options: skip,
error: CalendarError,
functions: [
Self::try_new_for_locale_unstable,
try_new_for_locale_with_any_provider,
try_new_for_locale_with_buffer_provider
]
);
pub fn try_new_for_locale_unstable<P>(
provider: &P,
locale: &DataLocale,
) -> Result<Self, CalendarError>
where
P: DataProvider<crate::provider::JapaneseErasV1Marker>
+ DataProvider<crate::provider::JapaneseExtendedErasV1Marker>
+ ?Sized,
{
let kind = AnyCalendarKind::from_data_locale_with_fallback(locale);
Self::try_new_unstable(provider, kind)
}
fn calendar_name(&self) -> &'static str {
match *self {
Self::Gregorian(_) => "Gregorian",
Self::Buddhist(_) => "Buddhist",
Self::Japanese(_) => "Japanese",
Self::JapaneseExtended(_) => "Japanese (Historical era data)",
Self::Ethiopian(_) => "Ethiopian",
Self::Indian(_) => "Indian",
Self::Coptic(_) => "Coptic",
Self::Iso(_) => "Iso",
}
}
pub fn kind(&self) -> AnyCalendarKind {
match *self {
Self::Gregorian(_) => AnyCalendarKind::Gregorian,
Self::Buddhist(_) => AnyCalendarKind::Buddhist,
Self::Japanese(_) => AnyCalendarKind::Japanese,
Self::JapaneseExtended(_) => AnyCalendarKind::JapaneseExtended,
#[allow(clippy::expect_used)] Self::Ethiopian(ref e) => e
.any_calendar_kind()
.expect("Ethiopian calendar known to have an AnyCalendarKind"),
Self::Indian(_) => AnyCalendarKind::Indian,
Self::Coptic(_) => AnyCalendarKind::Coptic,
Self::Iso(_) => AnyCalendarKind::Iso,
}
}
pub fn convert_any_date<'a>(
&'a self,
date: &Date<impl AsCalendar<Calendar = AnyCalendar>>,
) -> Date<Ref<'a, AnyCalendar>> {
if self.kind() != date.calendar.as_calendar().kind() {
Date::new_from_iso(date.to_iso(), Ref(self))
} else {
Date {
inner: date.inner.clone(),
calendar: Ref(self),
}
}
}
pub fn convert_any_datetime<'a>(
&'a self,
date: &DateTime<impl AsCalendar<Calendar = AnyCalendar>>,
) -> DateTime<Ref<'a, AnyCalendar>> {
DateTime {
time: date.time,
date: self.convert_any_date(&date.date),
}
}
}
impl AnyDateInner {
fn calendar_name(&self) -> &'static str {
match *self {
AnyDateInner::Gregorian(_) => "Gregorian",
AnyDateInner::Buddhist(_) => "Buddhist",
AnyDateInner::Japanese(_) => "Japanese",
AnyDateInner::JapaneseExtended(_) => "Japanese (Historical era data)",
AnyDateInner::Ethiopian(_) => "Ethiopian",
AnyDateInner::Indian(_) => "Indian",
AnyDateInner::Coptic(_) => "Coptic",
AnyDateInner::Iso(_) => "Iso",
}
}
}
#[non_exhaustive]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum AnyCalendarKind {
Gregorian,
Buddhist,
Japanese,
JapaneseExtended,
Ethiopian,
EthiopianAmeteAlem,
Indian,
Coptic,
Iso,
}
impl AnyCalendarKind {
pub fn get_for_bcp47_string(x: &str) -> Option<Self> {
Self::get_for_bcp47_bytes(x.as_bytes())
}
pub fn get_for_bcp47_bytes(x: &[u8]) -> Option<Self> {
Some(match x {
b"gregory" => AnyCalendarKind::Gregorian,
b"buddhist" => AnyCalendarKind::Buddhist,
b"japanese" => AnyCalendarKind::Japanese,
b"japanext" => AnyCalendarKind::JapaneseExtended,
b"indian" => AnyCalendarKind::Indian,
b"coptic" => AnyCalendarKind::Coptic,
b"iso" => AnyCalendarKind::Iso,
b"ethiopic" => AnyCalendarKind::Ethiopian,
b"ethioaa" => AnyCalendarKind::EthiopianAmeteAlem,
_ => return None,
})
}
pub fn get_for_bcp47_value(x: &Value) -> Option<Self> {
Some(if *x == value!("gregory") {
AnyCalendarKind::Gregorian
} else if *x == value!("buddhist") {
AnyCalendarKind::Buddhist
} else if *x == value!("japanese") {
AnyCalendarKind::Japanese
} else if *x == value!("japanext") {
AnyCalendarKind::JapaneseExtended
} else if *x == value!("indian") {
AnyCalendarKind::Indian
} else if *x == value!("coptic") {
AnyCalendarKind::Coptic
} else if *x == value!("iso") {
AnyCalendarKind::Iso
} else if *x == value!("ethiopic") {
AnyCalendarKind::Ethiopian
} else if *x == value!("ethioaa") {
AnyCalendarKind::EthiopianAmeteAlem
} else {
return None;
})
}
pub fn as_bcp47_string(self) -> &'static str {
match self {
AnyCalendarKind::Gregorian => "gregory",
AnyCalendarKind::Buddhist => "buddhist",
AnyCalendarKind::Japanese => "japanese",
AnyCalendarKind::JapaneseExtended => "japanext",
AnyCalendarKind::Indian => "indian",
AnyCalendarKind::Coptic => "coptic",
AnyCalendarKind::Iso => "iso",
AnyCalendarKind::Ethiopian => "ethiopic",
AnyCalendarKind::EthiopianAmeteAlem => "ethioaa",
}
}
pub fn as_bcp47_value(self) -> Value {
match self {
AnyCalendarKind::Gregorian => value!("gregory"),
AnyCalendarKind::Buddhist => value!("buddhist"),
AnyCalendarKind::Japanese => value!("japanese"),
AnyCalendarKind::JapaneseExtended => value!("japanext"),
AnyCalendarKind::Indian => value!("indian"),
AnyCalendarKind::Coptic => value!("coptic"),
AnyCalendarKind::Iso => value!("iso"),
AnyCalendarKind::Ethiopian => value!("ethiopic"),
AnyCalendarKind::EthiopianAmeteAlem => value!("ethioaa"),
}
}
pub fn get_for_locale(l: &Locale) -> Option<Self> {
l.extensions
.unicode
.keywords
.get(&key!("ca"))
.and_then(Self::get_for_bcp47_value)
}
fn get_for_data_locale(l: &DataLocale) -> Option<Self> {
l.get_unicode_ext(&key!("ca"))
.and_then(|v| Self::get_for_bcp47_value(&v))
}
fn from_data_locale_with_fallback(l: &DataLocale) -> Self {
if let Some(kind) = Self::get_for_data_locale(l) {
kind
} else {
let lang = l.language();
if lang == language!("th") {
Self::Buddhist
} else {
Self::Gregorian
}
}
}
}
impl fmt::Display for AnyCalendarKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl<C: IntoAnyCalendar> From<C> for AnyCalendar {
fn from(c: C) -> AnyCalendar {
c.to_any()
}
}
pub trait IntoAnyCalendar: Calendar + Sized {
fn to_any(self) -> AnyCalendar;
fn to_any_cloned(&self) -> AnyCalendar;
fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner;
}
impl IntoAnyCalendar for Gregorian {
fn to_any(self) -> AnyCalendar {
AnyCalendar::Gregorian(Gregorian)
}
fn to_any_cloned(&self) -> AnyCalendar {
AnyCalendar::Gregorian(Gregorian)
}
fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
AnyDateInner::Gregorian(*d)
}
}
impl IntoAnyCalendar for Buddhist {
fn to_any(self) -> AnyCalendar {
AnyCalendar::Buddhist(Buddhist)
}
fn to_any_cloned(&self) -> AnyCalendar {
AnyCalendar::Buddhist(Buddhist)
}
fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
AnyDateInner::Buddhist(*d)
}
}
impl IntoAnyCalendar for Japanese {
fn to_any(self) -> AnyCalendar {
AnyCalendar::Japanese(self)
}
fn to_any_cloned(&self) -> AnyCalendar {
AnyCalendar::Japanese(self.clone())
}
fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
AnyDateInner::Japanese(*d)
}
}
impl IntoAnyCalendar for JapaneseExtended {
fn to_any(self) -> AnyCalendar {
AnyCalendar::JapaneseExtended(self)
}
fn to_any_cloned(&self) -> AnyCalendar {
AnyCalendar::JapaneseExtended(self.clone())
}
fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
AnyDateInner::JapaneseExtended(*d)
}
}
impl IntoAnyCalendar for Ethiopian {
fn to_any(self) -> AnyCalendar {
AnyCalendar::Ethiopian(self)
}
fn to_any_cloned(&self) -> AnyCalendar {
AnyCalendar::Ethiopian(*self)
}
fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
AnyDateInner::Ethiopian(*d)
}
}
impl IntoAnyCalendar for Indian {
fn to_any(self) -> AnyCalendar {
AnyCalendar::Indian(Indian)
}
fn to_any_cloned(&self) -> AnyCalendar {
AnyCalendar::Indian(Indian)
}
fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
AnyDateInner::Indian(*d)
}
}
impl IntoAnyCalendar for Coptic {
fn to_any(self) -> AnyCalendar {
AnyCalendar::Coptic(Coptic)
}
fn to_any_cloned(&self) -> AnyCalendar {
AnyCalendar::Coptic(Coptic)
}
fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
AnyDateInner::Coptic(*d)
}
}
impl IntoAnyCalendar for Iso {
fn to_any(self) -> AnyCalendar {
AnyCalendar::Iso(Iso)
}
fn to_any_cloned(&self) -> AnyCalendar {
AnyCalendar::Iso(Iso)
}
fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner {
AnyDateInner::Iso(*d)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Ref;
use core::convert::TryInto;
fn single_test_roundtrip(
calendar: Ref<AnyCalendar>,
era: &str,
year: i32,
month_code: &str,
day: u8,
) {
let era = types::Era(era.parse().expect("era must parse"));
let month = types::MonthCode(month_code.parse().expect("month code must parse"));
let date = Date::try_new_from_codes(era, year, month, day, calendar).unwrap_or_else(|e| {
panic!(
"Failed to construct date for {} with {:?}, {}, {}, {}: {}",
calendar.debug_name(),
era,
year,
month,
day,
e,
)
});
let roundtrip_year = date.year();
let roundtrip_era = roundtrip_year.era;
let roundtrip_year = roundtrip_year.number;
let roundtrip_month = date.month().code;
let roundtrip_day = date.day_of_month().0.try_into().expect("Must fit in u8");
assert_eq!(
(era, year, month, day),
(
roundtrip_era,
roundtrip_year,
roundtrip_month,
roundtrip_day
),
"Failed to roundtrip for calendar {}",
calendar.debug_name()
);
let iso = date.to_iso();
let reconstructed = Date::new_from_iso(iso, calendar);
assert_eq!(
date, reconstructed,
"Failed to roundtrip via iso with {era:?}, {year}, {month}, {day}"
)
}
fn single_test_error(
calendar: Ref<AnyCalendar>,
era: &str,
year: i32,
month_code: &str,
day: u8,
error: CalendarError,
) {
let era = types::Era(era.parse().expect("era must parse"));
let month = types::MonthCode(month_code.parse().expect("month code must parse"));
let date = Date::try_new_from_codes(era, year, month, day, calendar);
assert_eq!(
date,
Err(error),
"Construction with {era:?}, {year}, {month}, {day} did not return {error:?}"
)
}
#[test]
#[cfg(feature = "serde")]
fn test_any_construction() {
let buddhist = AnyCalendar::try_new_with_buffer_provider(
&icu_testdata::buffer(),
AnyCalendarKind::Buddhist,
)
.expect("Calendar construction must succeed");
let coptic = AnyCalendar::try_new_with_buffer_provider(
&icu_testdata::buffer(),
AnyCalendarKind::Coptic,
)
.expect("Calendar construction must succeed");
let ethiopian = AnyCalendar::try_new_with_buffer_provider(
&icu_testdata::buffer(),
AnyCalendarKind::Ethiopian,
)
.expect("Calendar construction must succeed");
let ethioaa = AnyCalendar::try_new_with_buffer_provider(
&icu_testdata::buffer(),
AnyCalendarKind::EthiopianAmeteAlem,
)
.expect("Calendar construction must succeed");
let gregorian = AnyCalendar::try_new_with_buffer_provider(
&icu_testdata::buffer(),
AnyCalendarKind::Gregorian,
)
.expect("Calendar construction must succeed");
let indian = AnyCalendar::try_new_with_buffer_provider(
&icu_testdata::buffer(),
AnyCalendarKind::Indian,
)
.expect("Calendar construction must succeed");
let japanese = AnyCalendar::try_new_with_buffer_provider(
&icu_testdata::buffer(),
AnyCalendarKind::Japanese,
)
.expect("Calendar construction must succeed");
let japanext = AnyCalendar::try_new_with_buffer_provider(
&icu_testdata::buffer(),
AnyCalendarKind::JapaneseExtended,
)
.expect("Calendar construction must succeed");
let buddhist = Ref(&buddhist);
let coptic = Ref(&coptic);
let ethiopian = Ref(ðiopian);
let ethioaa = Ref(ðioaa);
let gregorian = Ref(&gregorian);
let indian = Ref(&indian);
let japanese = Ref(&japanese);
let japanext = Ref(&japanext);
single_test_roundtrip(buddhist, "be", 100, "M03", 1);
single_test_roundtrip(buddhist, "be", 2000, "M03", 1);
single_test_roundtrip(buddhist, "be", -100, "M03", 1);
single_test_error(
buddhist,
"be",
100,
"M13",
1,
CalendarError::UnknownMonthCode("M13".parse().unwrap(), "Buddhist"),
);
single_test_roundtrip(coptic, "ad", 100, "M03", 1);
single_test_roundtrip(coptic, "ad", 2000, "M03", 1);
single_test_roundtrip(coptic, "ad", 100, "M13", 1);
single_test_error(
coptic,
"ad",
100,
"M14",
1,
CalendarError::UnknownMonthCode("M14".parse().unwrap(), "Coptic"),
);
single_test_error(coptic, "ad", 0, "M03", 1, CalendarError::OutOfRange);
single_test_error(coptic, "bd", 0, "M03", 1, CalendarError::OutOfRange);
single_test_roundtrip(ethiopian, "incar", 100, "M03", 1);
single_test_roundtrip(ethiopian, "incar", 2000, "M03", 1);
single_test_roundtrip(ethiopian, "incar", 2000, "M13", 1);
single_test_error(ethiopian, "incar", 0, "M03", 1, CalendarError::OutOfRange);
single_test_error(
ethiopian,
"pre-incar",
0,
"M03",
1,
CalendarError::OutOfRange,
);
single_test_error(
ethiopian,
"incar",
100,
"M14",
1,
CalendarError::UnknownMonthCode("M14".parse().unwrap(), "Ethiopian"),
);
single_test_roundtrip(ethioaa, "mundi", 7000, "M13", 1);
single_test_roundtrip(ethioaa, "mundi", 7000, "M13", 1);
single_test_error(
ethiopian,
"mundi",
100,
"M14",
1,
CalendarError::UnknownMonthCode("M14".parse().unwrap(), "Ethiopian"),
);
single_test_roundtrip(gregorian, "ce", 100, "M03", 1);
single_test_roundtrip(gregorian, "ce", 2000, "M03", 1);
single_test_roundtrip(gregorian, "bce", 100, "M03", 1);
single_test_error(gregorian, "ce", 0, "M03", 1, CalendarError::OutOfRange);
single_test_error(gregorian, "bce", 0, "M03", 1, CalendarError::OutOfRange);
single_test_error(
gregorian,
"bce",
100,
"M13",
1,
CalendarError::UnknownMonthCode("M13".parse().unwrap(), "Gregorian"),
);
single_test_roundtrip(indian, "saka", 100, "M03", 1);
single_test_roundtrip(indian, "saka", 2000, "M12", 1);
single_test_roundtrip(indian, "saka", -100, "M03", 1);
single_test_roundtrip(indian, "saka", 0, "M03", 1);
single_test_error(
indian,
"saka",
100,
"M13",
1,
CalendarError::UnknownMonthCode("M13".parse().unwrap(), "Indian"),
);
single_test_roundtrip(japanese, "reiwa", 3, "M03", 1);
single_test_roundtrip(japanese, "heisei", 6, "M12", 1);
single_test_roundtrip(japanese, "meiji", 10, "M03", 1);
single_test_roundtrip(japanese, "ce", 1000, "M03", 1);
single_test_roundtrip(japanese, "bce", 10, "M03", 1);
single_test_error(japanese, "ce", 0, "M03", 1, CalendarError::OutOfRange);
single_test_error(japanese, "bce", 0, "M03", 1, CalendarError::OutOfRange);
single_test_error(
japanese,
"reiwa",
2,
"M13",
1,
CalendarError::UnknownMonthCode("M13".parse().unwrap(), "Japanese (Modern eras only)"),
);
single_test_roundtrip(japanext, "reiwa", 3, "M03", 1);
single_test_roundtrip(japanext, "heisei", 6, "M12", 1);
single_test_roundtrip(japanext, "meiji", 10, "M03", 1);
single_test_roundtrip(japanext, "tenpyokampo-749", 1, "M04", 20);
single_test_roundtrip(japanext, "ce", 100, "M03", 1);
single_test_roundtrip(japanext, "bce", 10, "M03", 1);
single_test_error(japanext, "ce", 0, "M03", 1, CalendarError::OutOfRange);
single_test_error(japanext, "bce", 0, "M03", 1, CalendarError::OutOfRange);
single_test_error(
japanext,
"reiwa",
2,
"M13",
1,
CalendarError::UnknownMonthCode(
"M13".parse().unwrap(),
"Japanese (With historical eras)",
),
);
}
}