diff --git a/components/calendar/src/any_calendar.rs b/components/calendar/src/any_calendar.rs index e951fb5bb2e..d1816f0352f 100644 --- a/components/calendar/src/any_calendar.rs +++ b/components/calendar/src/any_calendar.rs @@ -6,7 +6,7 @@ use crate::cal::iso::IsoDateInner; use crate::cal::*; -use crate::error::DateError; +use crate::error::{DateError, DateFromFieldsError}; use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::{DateFields, YearInfo}; @@ -279,7 +279,7 @@ impl Calendar for AnyCalendar { &self, fields: DateFields, options: DateFromFieldsOptions, - ) -> Result { + ) -> Result { Ok(match_cal!(match self: (c) => c.from_fields(fields, options)?)) } diff --git a/components/calendar/src/cal/abstract_gregorian.rs b/components/calendar/src/cal/abstract_gregorian.rs index 971398e15f4..0967e4d1776 100644 --- a/components/calendar/src/cal/abstract_gregorian.rs +++ b/components/calendar/src/cal/abstract_gregorian.rs @@ -6,7 +6,7 @@ use crate::cal::iso::{IsoDateInner, IsoEra}; use crate::calendar_arithmetic::{ ArithmeticDate, ArithmeticDateBuilder, CalendarArithmetic, DateFieldsResolver, }; -use crate::error::DateError; +use crate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError}; use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::preferences::CalendarAlgorithm; @@ -22,7 +22,7 @@ pub(crate) trait GregorianYears: Clone + core::fmt::Debug { // Positive if after 0 CE const EXTENDED_YEAR_OFFSET: i32 = 0; - fn extended_from_era_year(&self, era: Option<&str>, year: i32) -> Result; + fn extended_from_era_year(&self, era: Option<&str>, year: i32) -> Result; fn era_year_from_extended(&self, extended_year: i32, month: u8, day: u8) -> EraYear; @@ -88,7 +88,11 @@ impl DateFieldsResolver for AbstractGregorian { type YearInfo = i32; #[inline] - fn year_info_from_era(&self, era: &str, era_year: i32) -> Result { + fn year_info_from_era( + &self, + era: &str, + era_year: i32, + ) -> Result { Ok(self.0.extended_from_era_year(Some(era), era_year)? + Y::EXTENDED_YEAR_OFFSET) } @@ -102,7 +106,7 @@ impl DateFieldsResolver for AbstractGregorian { &self, _month_code: types::MonthCode, _day: u8, - ) -> Result { + ) -> Result { Ok(REFERENCE_YEAR) } } @@ -118,10 +122,10 @@ impl Calendar for AbstractGregorian { &self, fields: types::DateFields, options: DateFromFieldsOptions, - ) -> Result { + ) -> Result { let builder = ArithmeticDateBuilder::try_from_fields(fields, self, options)?; - ArithmeticDate::try_from_builder(builder, options) - .map_err(|e| e.maybe_with_month_code(fields.month_code)) + let arithmetic_date = ArithmeticDate::try_from_builder(builder, options)?; + Ok(arithmetic_date) } fn from_rata_die(&self, date: RataDie) -> Self::DateInner { @@ -232,7 +236,7 @@ macro_rules! impl_with_abstract_gregorian { &self, fields: crate::types::DateFields, options: crate::options::DateFromFieldsOptions, - ) -> Result { + ) -> Result { let $self_ident = self; crate::cal::abstract_gregorian::AbstractGregorian($eras_expr) .from_fields(fields, options) diff --git a/components/calendar/src/cal/buddhist.rs b/components/calendar/src/cal/buddhist.rs index f7d2b726a17..70c778a196c 100644 --- a/components/calendar/src/cal/buddhist.rs +++ b/components/calendar/src/cal/buddhist.rs @@ -2,6 +2,7 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use crate::error::UnknownEraError; use crate::preferences::CalendarAlgorithm; use crate::{ cal::abstract_gregorian::{impl_with_abstract_gregorian, GregorianYears}, @@ -47,10 +48,10 @@ pub(crate) struct BuddhistEra; impl GregorianYears for BuddhistEra { const EXTENDED_YEAR_OFFSET: i32 = -543; - fn extended_from_era_year(&self, era: Option<&str>, year: i32) -> Result { + fn extended_from_era_year(&self, era: Option<&str>, year: i32) -> Result { match era { Some("be") | None => Ok(year), - _ => Err(DateError::UnknownEra), + _ => Err(UnknownEraError), } } diff --git a/components/calendar/src/cal/chinese.rs b/components/calendar/src/cal/chinese.rs index ba266b60714..a96a324e40c 100644 --- a/components/calendar/src/cal/chinese.rs +++ b/components/calendar/src/cal/chinese.rs @@ -7,7 +7,9 @@ use crate::calendar_arithmetic::DateFieldsResolver; use crate::calendar_arithmetic::{ ArithmeticDate, ArithmeticDateBuilder, CalendarArithmetic, ToExtendedYear, }; -use crate::error::DateError; +use crate::error::{ + DateError, DateFromFieldsError, EcmaReferenceYearError, MonthCodeError, UnknownEraError, +}; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::options::{DateFromFieldsOptions, Overflow}; use crate::provider::chinese_based::PackedChineseBasedYearInfo; @@ -122,8 +124,8 @@ pub trait Rules: Clone + core::fmt::Debug + crate::cal::scaffold::UnstableSealed &self, _month_code: types::MonthCode, _day: u8, - ) -> Result { - Err(DateError::NotEnoughFields) + ) -> Result { + Err(EcmaReferenceYearError::NotEnoughFields) } /// The debug name for the calendar defined by these [`Rules`]. @@ -201,10 +203,12 @@ impl Rules for China { } } - fn ecma_reference_year(&self, month_code: types::MonthCode, day: u8) -> Result { - let Some((number, is_leap)) = month_code.parsed() else { - return Err(DateError::UnknownMonthCode(month_code)); - }; + fn ecma_reference_year( + &self, + month_code: types::MonthCode, + day: u8, + ) -> Result { + let (number, is_leap) = month_code.try_parse()?; // Computed by `generate_reference_years` Ok(match (number, is_leap, day > 29) { (1, false, false) => 1972, @@ -258,7 +262,7 @@ impl Rules for China { (12, false, true) => 1971, (12, true, false) => 1878, (12, true, true) => 1783, - _ => return Err(DateError::UnknownMonthCode(month_code)), + _ => return Err(EcmaReferenceYearError::UnknownMonthCodeForCalendar), }) } @@ -380,10 +384,12 @@ impl Rules for Korea { } } - fn ecma_reference_year(&self, month_code: types::MonthCode, day: u8) -> Result { - let Some((number, is_leap)) = month_code.parsed() else { - return Err(DateError::UnknownMonthCode(month_code)); - }; + fn ecma_reference_year( + &self, + month_code: types::MonthCode, + day: u8, + ) -> Result { + let (number, is_leap) = month_code.try_parse()?; // Computed by `generate_reference_years` Ok(match (number, is_leap, day > 29) { (1, false, false) => 1972, @@ -437,7 +443,7 @@ impl Rules for Korea { (12, false, true) => 1971, (12, true, false) => 1878, (12, true, true) => 1783, - _ => return Err(DateError::UnknownMonthCode(month_code)), + _ => return Err(EcmaReferenceYearError::UnknownMonthCodeForCalendar), }) } @@ -554,9 +560,13 @@ impl DateFieldsResolver for LunarChinese { type YearInfo = LunarChineseYearData; #[inline] - fn year_info_from_era(&self, _era: &str, _era_year: i32) -> Result { + fn year_info_from_era( + &self, + _era: &str, + _era_year: i32, + ) -> Result { // This calendar has no era codes - Err(DateError::UnknownEra) + Err(UnknownEraError) } #[inline] @@ -569,7 +579,7 @@ impl DateFieldsResolver for LunarChinese { &self, month_code: types::MonthCode, day: u8, - ) -> Result { + ) -> Result { Ok(self .0 .year_data(self.0.ecma_reference_year(month_code, day)?)) @@ -580,15 +590,17 @@ impl DateFieldsResolver for LunarChinese { year: &Self::YearInfo, month_code: types::MonthCode, options: DateFromFieldsOptions, - ) -> Result { + ) -> Result { match year.parse_month_code(month_code) { ComputedOrdinalMonth::Exact(val) => Ok(val), - ComputedOrdinalMonth::LeapToNormal(val) - if options.overflow == Some(Overflow::Constrain) => - { - Ok(val) + ComputedOrdinalMonth::LeapToNormal(val) => { + if options.overflow == Some(Overflow::Constrain) { + Ok(val) + } else { + Err(MonthCodeError::UnknownMonthCodeForYear) + } } - _ => Err(DateError::UnknownMonthCode(month_code)), + ComputedOrdinalMonth::NotFound => Err(MonthCodeError::UnknownMonthCodeForCalendar), } } @@ -611,11 +623,10 @@ impl Calendar for LunarChinese { &self, fields: types::DateFields, options: DateFromFieldsOptions, - ) -> Result { + ) -> Result { let builder = ArithmeticDateBuilder::try_from_fields(fields, self, options)?; - Ok(ChineseDateInner(ArithmeticDate::try_from_builder( - builder, options, - )?)) + let arithmetic_date = ArithmeticDate::try_from_builder(builder, options)?; + Ok(ChineseDateInner(arithmetic_date)) } fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { @@ -1709,7 +1720,7 @@ mod test { let cal = LunarChinese::new_china(); assert!(matches!( Date::try_from_fields(fields, options, cal).unwrap_err(), - DateError::Range { .. } + DateFromFieldsError::Range { .. } )); } diff --git a/components/calendar/src/cal/coptic.rs b/components/calendar/src/cal/coptic.rs index af1c9fb0d1e..d218bfe08d3 100644 --- a/components/calendar/src/cal/coptic.rs +++ b/components/calendar/src/cal/coptic.rs @@ -5,7 +5,9 @@ use crate::cal::iso::{Iso, IsoDateInner}; use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; use crate::calendar_arithmetic::{ArithmeticDateBuilder, DateFieldsResolver}; -use crate::error::DateError; +use crate::error::{ + DateError, DateFromFieldsError, EcmaReferenceYearError, MonthCodeError, UnknownEraError, +}; use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::{types, Calendar, Date, RangeError}; @@ -85,10 +87,14 @@ impl DateFieldsResolver for Coptic { type YearInfo = i32; #[inline] - fn year_info_from_era(&self, era: &str, era_year: i32) -> Result { + fn year_info_from_era( + &self, + era: &str, + era_year: i32, + ) -> Result { match era { "am" => Ok(era_year), - _ => Err(DateError::UnknownEra), + _ => Err(UnknownEraError), } } @@ -102,7 +108,7 @@ impl DateFieldsResolver for Coptic { &self, month_code: types::MonthCode, day: u8, - ) -> Result { + ) -> Result { Coptic::reference_year_from_month_day(month_code, day) } @@ -112,10 +118,10 @@ impl DateFieldsResolver for Coptic { _year: &Self::YearInfo, month_code: types::MonthCode, _options: DateFromFieldsOptions, - ) -> Result { - match month_code.parsed() { - Some((month_number @ 1..=13, false)) => Ok(month_number), - _ => Err(DateError::UnknownMonthCode(month_code)), + ) -> Result { + match month_code.try_parse()? { + (month_number @ 1..=13, false) => Ok(month_number), + _ => Err(MonthCodeError::UnknownMonthCodeForCalendar), } } } @@ -124,10 +130,8 @@ impl Coptic { pub(crate) fn reference_year_from_month_day( month_code: types::MonthCode, day: u8, - ) -> Result { - let (ordinal_month, _is_leap) = month_code - .parsed() - .ok_or(DateError::UnknownMonthCode(month_code))?; + ) -> Result { + let (ordinal_month, _is_leap) = month_code.try_parse()?; // December 31, 1972 occurs on 4th month, 22nd day, 1689 AM let anno_martyrum_year = if ordinal_month < 4 || (ordinal_month == 4 && day <= 22) { 1689 @@ -153,11 +157,10 @@ impl Calendar for Coptic { &self, fields: types::DateFields, options: DateFromFieldsOptions, - ) -> Result { + ) -> Result { let builder = ArithmeticDateBuilder::try_from_fields(fields, self, options)?; - ArithmeticDate::try_from_builder(builder, options) - .map(CopticDateInner) - .map_err(|e| e.maybe_with_month_code(fields.month_code)) + let arithmetic_date = ArithmeticDate::try_from_builder(builder, options)?; + Ok(CopticDateInner(arithmetic_date)) } fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { diff --git a/components/calendar/src/cal/ethiopian.rs b/components/calendar/src/cal/ethiopian.rs index 64a950d3a82..d012c61c6ac 100644 --- a/components/calendar/src/cal/ethiopian.rs +++ b/components/calendar/src/cal/ethiopian.rs @@ -6,7 +6,9 @@ use crate::cal::coptic::CopticDateInner; use crate::cal::iso::IsoDateInner; use crate::cal::Coptic; use crate::calendar_arithmetic::{ArithmeticDate, ArithmeticDateBuilder, DateFieldsResolver}; -use crate::error::DateError; +use crate::error::{ + DateError, DateFromFieldsError, EcmaReferenceYearError, MonthCodeError, UnknownEraError, +}; use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::DateFields; @@ -75,11 +77,15 @@ impl DateFieldsResolver for Ethiopian { type YearInfo = i32; #[inline] - fn year_info_from_era(&self, era: &str, era_year: i32) -> Result { + fn year_info_from_era( + &self, + era: &str, + era_year: i32, + ) -> Result { match (self.era_style(), era) { (EthiopianEraStyle::AmeteMihret, "am") => Ok(era_year + AMETE_MIHRET_OFFSET), (_, "aa") => Ok(era_year + AMETE_ALEM_OFFSET), - (_, _) => Err(DateError::UnknownEra), + (_, _) => Err(UnknownEraError), } } @@ -98,7 +104,7 @@ impl DateFieldsResolver for Ethiopian { &self, month_code: types::MonthCode, day: u8, - ) -> Result { + ) -> Result { crate::cal::Coptic::reference_year_from_month_day(month_code, day) } @@ -108,10 +114,10 @@ impl DateFieldsResolver for Ethiopian { _year: &Self::YearInfo, month_code: types::MonthCode, _options: DateFromFieldsOptions, - ) -> Result { - match month_code.parsed() { - Some((month_number @ 1..=13, false)) => Ok(month_number), - _ => Err(DateError::UnknownMonthCode(month_code)), + ) -> Result { + match month_code.try_parse()? { + (month_number @ 1..=13, false) => Ok(month_number), + _ => Err(MonthCodeError::UnknownMonthCodeForCalendar), } } } @@ -126,12 +132,10 @@ impl Calendar for Ethiopian { &self, fields: DateFields, options: DateFromFieldsOptions, - ) -> Result { + ) -> Result { let builder = ArithmeticDateBuilder::try_from_fields(fields, self, options)?; - ArithmeticDate::try_from_builder(builder, options) - .map(CopticDateInner) - .map(EthiopianDateInner) - .map_err(|e| e.maybe_with_month_code(fields.month_code)) + let arithmetic_date = ArithmeticDate::try_from_builder(builder, options)?; + Ok(EthiopianDateInner(CopticDateInner(arithmetic_date))) } fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { diff --git a/components/calendar/src/cal/gregorian.rs b/components/calendar/src/cal/gregorian.rs index c98ae3233d5..c9be5cdcb0c 100644 --- a/components/calendar/src/cal/gregorian.rs +++ b/components/calendar/src/cal/gregorian.rs @@ -4,6 +4,7 @@ use crate::cal::abstract_gregorian::{impl_with_abstract_gregorian, GregorianYears}; use crate::calendar_arithmetic::ArithmeticDate; +use crate::error::UnknownEraError; use crate::preferences::CalendarAlgorithm; use crate::{types, Date, DateError, RangeError}; use tinystr::tinystr; @@ -14,12 +15,12 @@ impl_with_abstract_gregorian!(crate::cal::Gregorian, GregorianDateInner, CeBce, pub(crate) struct CeBce; impl GregorianYears for CeBce { - fn extended_from_era_year(&self, era: Option<&str>, year: i32) -> Result { + fn extended_from_era_year(&self, era: Option<&str>, year: i32) -> Result { match era { None => Ok(year), Some("ad" | "ce") => Ok(year), Some("bce" | "bc") => Ok(1 - year), - Some(_) => Err(DateError::UnknownEra), + Some(_) => Err(UnknownEraError), } } diff --git a/components/calendar/src/cal/hebrew.rs b/components/calendar/src/cal/hebrew.rs index 35b0d7889aa..c0e7d3e712c 100644 --- a/components/calendar/src/cal/hebrew.rs +++ b/components/calendar/src/cal/hebrew.rs @@ -7,7 +7,9 @@ use crate::calendar_arithmetic::ArithmeticDateBuilder; use crate::calendar_arithmetic::{ ArithmeticDate, CalendarArithmetic, DateFieldsResolver, ToExtendedYear, }; -use crate::error::DateError; +use crate::error::{ + DateError, DateFromFieldsError, EcmaReferenceYearError, MonthCodeError, UnknownEraError, +}; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::options::{DateFromFieldsOptions, Overflow}; use crate::types::{DateFields, MonthInfo}; @@ -119,10 +121,14 @@ impl DateFieldsResolver for Hebrew { type YearInfo = HebrewYearInfo; #[inline] - fn year_info_from_era(&self, era: &str, era_year: i32) -> Result { + fn year_info_from_era( + &self, + era: &str, + era_year: i32, + ) -> Result { match era { "am" => Ok(HebrewYearInfo::compute(era_year)), - _ => Err(DateError::UnknownEra), + _ => Err(UnknownEraError), } } @@ -135,7 +141,8 @@ impl DateFieldsResolver for Hebrew { &self, month_code: types::MonthCode, day: u8, - ) -> Result { + ) -> Result { + month_code.try_parse()?; // return InvalidMonthCode let month_code_str = month_code.0.as_str(); // December 31, 1972 occurs on 4th month, 26th day, 5733 AM let hebrew_year = match month_code_str { @@ -167,7 +174,7 @@ impl DateFieldsResolver for Hebrew { "M11" => 5732, "M12" => 5732, _ => { - return Err(DateError::UnknownMonthCode(month_code)); + return Err(EcmaReferenceYearError::UnknownMonthCodeForCalendar); } }; Ok(HebrewYearInfo::compute(hebrew_year)) @@ -178,8 +185,9 @@ impl DateFieldsResolver for Hebrew { year: &Self::YearInfo, month_code: types::MonthCode, options: DateFromFieldsOptions, - ) -> Result { + ) -> Result { let is_leap_year = year.keviyah.is_leap(); + month_code.try_parse()?; // return InvalidMonthCode let month_code_str = month_code.0.as_str(); let ordinal_month = if is_leap_year { match month_code_str { @@ -197,7 +205,7 @@ impl DateFieldsResolver for Hebrew { "M11" => 12, "M12" => 13, _ => { - return Err(DateError::UnknownMonthCode(month_code)); + return Err(MonthCodeError::UnknownMonthCodeForCalendar); } } } else { @@ -207,8 +215,14 @@ impl DateFieldsResolver for Hebrew { "M03" => 3, "M04" => 4, "M05" => 5, - // M05L maps to M06 in a common year - "M05L" if matches!(options.overflow, Some(Overflow::Constrain)) => 6, + "M05L" => { + // M05L maps to M06 in a common year + if matches!(options.overflow, Some(Overflow::Constrain)) { + 6 + } else { + return Err(MonthCodeError::UnknownMonthCodeForYear); + } + } "M06" => 6, "M07" => 7, "M08" => 8, @@ -217,7 +231,7 @@ impl DateFieldsResolver for Hebrew { "M11" => 11, "M12" => 12, _ => { - return Err(DateError::UnknownMonthCode(month_code)); + return Err(MonthCodeError::UnknownMonthCodeForCalendar); } } }; @@ -287,7 +301,7 @@ impl Calendar for Hebrew { &self, fields: DateFields, options: DateFromFieldsOptions, - ) -> Result { + ) -> Result { let builder = ArithmeticDateBuilder::try_from_fields(fields, self, options)?; Ok(HebrewDateInner(ArithmeticDate::try_from_builder( builder, options, diff --git a/components/calendar/src/cal/hijri.rs b/components/calendar/src/cal/hijri.rs index b194b02894d..e75e644378e 100644 --- a/components/calendar/src/cal/hijri.rs +++ b/components/calendar/src/cal/hijri.rs @@ -6,7 +6,7 @@ use crate::cal::iso::{Iso, IsoDateInner}; use crate::calendar_arithmetic::ToExtendedYear; use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; use crate::calendar_arithmetic::{ArithmeticDateBuilder, DateFieldsResolver}; -use crate::error::DateError; +use crate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError}; use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::provider::hijri::PackedHijriYearInfo; @@ -86,8 +86,8 @@ pub trait Rules: Clone + Debug + crate::cal::scaffold::UnstableSealed { &self, _month_code: types::MonthCode, _day: u8, - ) -> Result { - Err(DateError::NotEnoughFields) + ) -> Result { + Err(EcmaReferenceYearError::NotEnoughFields) } /// The BCP-47 [`CalendarAlgorithm`] for the Hijri calendar using these rules, if defined. @@ -251,9 +251,13 @@ impl Rules for UmmAlQura { ))) } - fn ecma_reference_year(&self, month_code: types::MonthCode, day: u8) -> Result { - let Some((ordinal_month, false)) = month_code.parsed() else { - return Err(DateError::UnknownMonthCode(month_code)); + fn ecma_reference_year( + &self, + month_code: types::MonthCode, + day: u8, + ) -> Result { + let (ordinal_month, false) = month_code.try_parse()? else { + return Err(EcmaReferenceYearError::UnknownMonthCodeForCalendar); }; Ok(match (ordinal_month, day) { @@ -276,7 +280,7 @@ impl Rules for UmmAlQura { (11, _) => 1391, (12, 30..) => 1390, (12, _) => 1391, - _ => return Err(DateError::UnknownMonthCode(month_code)), + _ => return Err(EcmaReferenceYearError::UnknownMonthCodeForCalendar), }) } @@ -337,9 +341,13 @@ impl Rules for TabularAlgorithm { }) } - fn ecma_reference_year(&self, month_code: types::MonthCode, day: u8) -> Result { - let Some((ordinal_month, false)) = month_code.parsed() else { - return Err(DateError::UnknownMonthCode(month_code)); + fn ecma_reference_year( + &self, + month_code: types::MonthCode, + day: u8, + ) -> Result { + let (ordinal_month, false) = month_code.try_parse()? else { + return Err(EcmaReferenceYearError::UnknownMonthCodeForCalendar); }; Ok(match (ordinal_month, day) { @@ -363,7 +371,7 @@ impl Rules for TabularAlgorithm { (11, _) => 1391, (12, 30..) => 1390, (12, _) => 1391, - _ => return Err(DateError::UnknownMonthCode(month_code)), + _ => return Err(EcmaReferenceYearError::UnknownMonthCodeForCalendar), }) } @@ -715,11 +723,15 @@ impl DateFieldsResolver for Hijri { type YearInfo = HijriYearData; #[inline] - fn year_info_from_era(&self, era: &str, era_year: i32) -> Result { + fn year_info_from_era( + &self, + era: &str, + era_year: i32, + ) -> Result { let extended_year = match era { "ah" => era_year, "bh" => 1 - era_year, - _ => return Err(DateError::UnknownEra), + _ => return Err(UnknownEraError), }; Ok(self.year_info_from_extended(extended_year)) } @@ -734,7 +746,7 @@ impl DateFieldsResolver for Hijri { &self, month_code: types::MonthCode, day: u8, - ) -> Result { + ) -> Result { Ok(self .0 .year_data(self.0.ecma_reference_year(month_code, day)?)) @@ -751,11 +763,10 @@ impl Calendar for Hijri { &self, fields: DateFields, options: DateFromFieldsOptions, - ) -> Result { + ) -> Result { let builder = ArithmeticDateBuilder::try_from_fields(fields, self, options)?; - ArithmeticDate::try_from_builder(builder, options) - .map(HijriDateInner) - .map_err(|e| e.maybe_with_month_code(fields.month_code)) + let arithmetic_date = ArithmeticDate::try_from_builder(builder, options)?; + Ok(HijriDateInner(arithmetic_date)) } fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { diff --git a/components/calendar/src/cal/indian.rs b/components/calendar/src/cal/indian.rs index 8e1c42dd45e..9cb55bd496f 100644 --- a/components/calendar/src/cal/indian.rs +++ b/components/calendar/src/cal/indian.rs @@ -5,7 +5,7 @@ use crate::cal::iso::{Iso, IsoDateInner}; use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; use crate::calendar_arithmetic::{ArithmeticDateBuilder, DateFieldsResolver}; -use crate::error::DateError; +use crate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError}; use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::DateFields; @@ -80,10 +80,14 @@ impl DateFieldsResolver for Indian { type YearInfo = i32; #[inline] - fn year_info_from_era(&self, era: &str, era_year: i32) -> Result { + fn year_info_from_era( + &self, + era: &str, + era_year: i32, + ) -> Result { match era { "shaka" => Ok(era_year), - _ => Err(DateError::UnknownEra), + _ => Err(UnknownEraError), } } @@ -97,10 +101,8 @@ impl DateFieldsResolver for Indian { &self, month_code: types::MonthCode, day: u8, - ) -> Result { - let (ordinal_month, _is_leap) = month_code - .parsed() - .ok_or(DateError::UnknownMonthCode(month_code))?; + ) -> Result { + let (ordinal_month, _is_leap) = month_code.try_parse()?; // December 31, 1972 occurs on 10th month, 10th day, 1894 Shaka // Note: 1894 Shaka is also a leap year let shaka_year = if ordinal_month < 10 || (ordinal_month == 10 && day <= 10) { @@ -122,11 +124,10 @@ impl Calendar for Indian { &self, fields: DateFields, options: DateFromFieldsOptions, - ) -> Result { + ) -> Result { let builder = ArithmeticDateBuilder::try_from_fields(fields, self, options)?; - ArithmeticDate::try_from_builder(builder, options) - .map(IndianDateInner) - .map_err(|e| e.maybe_with_month_code(fields.month_code)) + let arithmetic_date = ArithmeticDate::try_from_builder(builder, options)?; + Ok(IndianDateInner(arithmetic_date)) } fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { diff --git a/components/calendar/src/cal/iso.rs b/components/calendar/src/cal/iso.rs index 34b7734170a..f7ae0181587 100644 --- a/components/calendar/src/cal/iso.rs +++ b/components/calendar/src/cal/iso.rs @@ -4,6 +4,7 @@ use crate::cal::abstract_gregorian::{impl_with_abstract_gregorian, GregorianYears}; use crate::calendar_arithmetic::ArithmeticDate; +use crate::error::UnknownEraError; use crate::{types, Date, DateError, RangeError}; use tinystr::tinystr; @@ -30,10 +31,10 @@ impl_with_abstract_gregorian!(crate::cal::Iso, IsoDateInner, IsoEra, _x, IsoEra) pub(crate) struct IsoEra; impl GregorianYears for IsoEra { - fn extended_from_era_year(&self, era: Option<&str>, year: i32) -> Result { + fn extended_from_era_year(&self, era: Option<&str>, year: i32) -> Result { match era { Some("default") | None => Ok(year), - Some(_) => Err(DateError::UnknownEra), + Some(_) => Err(UnknownEraError), } } diff --git a/components/calendar/src/cal/japanese.rs b/components/calendar/src/cal/japanese.rs index 880e6a28ba7..f9889e22aea 100644 --- a/components/calendar/src/cal/japanese.rs +++ b/components/calendar/src/cal/japanese.rs @@ -5,7 +5,7 @@ use crate::cal::abstract_gregorian::{impl_with_abstract_gregorian, GregorianYears}; use crate::cal::gregorian::CeBce; use crate::calendar_arithmetic::ArithmeticDate; -use crate::error::DateError; +use crate::error::{DateError, UnknownEraError}; use crate::provider::{CalendarJapaneseExtendedV1, CalendarJapaneseModernV1, EraStartDate}; use crate::{types, AsCalendar, Date}; use icu_provider::prelude::*; @@ -169,13 +169,13 @@ const REIWA_START: EraStartDate = EraStartDate { }; impl GregorianYears for &'_ Japanese { - fn extended_from_era_year(&self, era: Option<&str>, year: i32) -> Result { + fn extended_from_era_year(&self, era: Option<&str>, year: i32) -> Result { if let Ok(g) = CeBce.extended_from_era_year(era, year) { return Ok(g); } let Some(era) = era else { // unreachable, handled by CeBce - return Err(DateError::UnknownEra); + return Err(UnknownEraError); }; // Avoid linear search by trying well known eras @@ -211,7 +211,7 @@ impl GregorianYears for &'_ Japanese { .iter() .rev() .find_map(|(s, e)| (e == era).then_some(s)) - .ok_or(DateError::UnknownEra)?; + .ok_or(UnknownEraError)?; Ok(era_start.year + year - 1) } diff --git a/components/calendar/src/cal/julian.rs b/components/calendar/src/cal/julian.rs index 95870bc47b9..74e32ae5909 100644 --- a/components/calendar/src/cal/julian.rs +++ b/components/calendar/src/cal/julian.rs @@ -5,7 +5,7 @@ use crate::cal::iso::{Iso, IsoDateInner}; use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; use crate::calendar_arithmetic::{ArithmeticDateBuilder, DateFieldsResolver}; -use crate::error::DateError; +use crate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError}; use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::DateFields; @@ -105,11 +105,15 @@ impl DateFieldsResolver for Julian { type YearInfo = i32; #[inline] - fn year_info_from_era(&self, era: &str, era_year: i32) -> Result { + fn year_info_from_era( + &self, + era: &str, + era_year: i32, + ) -> Result { match era { "ad" | "ce" => Ok(era_year), "bc" | "bce" => Ok(1 - era_year), - _ => Err(DateError::UnknownEra), + _ => Err(UnknownEraError), } } @@ -123,10 +127,8 @@ impl DateFieldsResolver for Julian { &self, month_code: types::MonthCode, day: u8, - ) -> Result { - let (ordinal_month, _is_leap) = month_code - .parsed() - .ok_or(DateError::UnknownMonthCode(month_code))?; + ) -> Result { + let (ordinal_month, _is_leap) = month_code.try_parse()?; // December 31, 1972 occurs on 12th month, 18th day, 1972 Old Style // Note: 1972 is a leap year let julian_year = if ordinal_month < 12 || (ordinal_month == 12 && day <= 18) { @@ -148,11 +150,10 @@ impl Calendar for Julian { &self, fields: DateFields, options: DateFromFieldsOptions, - ) -> Result { + ) -> Result { let builder = ArithmeticDateBuilder::try_from_fields(fields, self, options)?; - ArithmeticDate::try_from_builder(builder, options) - .map(JulianDateInner) - .map_err(|e| e.maybe_with_month_code(fields.month_code)) + let arithmetic_date = ArithmeticDate::try_from_builder(builder, options)?; + Ok(JulianDateInner(arithmetic_date)) } fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { diff --git a/components/calendar/src/cal/persian.rs b/components/calendar/src/cal/persian.rs index 1de3b1f8609..ac9b2ec2193 100644 --- a/components/calendar/src/cal/persian.rs +++ b/components/calendar/src/cal/persian.rs @@ -5,7 +5,7 @@ use crate::cal::iso::{Iso, IsoDateInner}; use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; use crate::calendar_arithmetic::{ArithmeticDateBuilder, DateFieldsResolver}; -use crate::error::DateError; +use crate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError}; use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::DateFields; @@ -79,10 +79,14 @@ impl DateFieldsResolver for Persian { type YearInfo = i32; #[inline] - fn year_info_from_era(&self, era: &str, era_year: i32) -> Result { + fn year_info_from_era( + &self, + era: &str, + era_year: i32, + ) -> Result { match era { "ap" | "sh" | "hs" => Ok(era_year), - _ => Err(DateError::UnknownEra), + _ => Err(UnknownEraError), } } @@ -96,10 +100,8 @@ impl DateFieldsResolver for Persian { &self, month_code: types::MonthCode, day: u8, - ) -> Result { - let (ordinal_month, _is_leap) = month_code - .parsed() - .ok_or(DateError::UnknownMonthCode(month_code))?; + ) -> Result { + let (ordinal_month, _is_leap) = month_code.try_parse()?; // December 31, 1972 occurs on 10th month, 10th day, 1351 AP let persian_year = if ordinal_month < 10 || (ordinal_month == 10 && day <= 10) { 1351 @@ -121,11 +123,10 @@ impl Calendar for Persian { &self, fields: DateFields, options: DateFromFieldsOptions, - ) -> Result { + ) -> Result { let builder = ArithmeticDateBuilder::try_from_fields(fields, self, options)?; - ArithmeticDate::try_from_builder(builder, options) - .map(PersianDateInner) - .map_err(|e| e.maybe_with_month_code(fields.month_code)) + let arithmetic_date = ArithmeticDate::try_from_builder(builder, options)?; + Ok(PersianDateInner(arithmetic_date)) } fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { diff --git a/components/calendar/src/cal/roc.rs b/components/calendar/src/cal/roc.rs index 21ff43eac8f..a85eab1954c 100644 --- a/components/calendar/src/cal/roc.rs +++ b/components/calendar/src/cal/roc.rs @@ -4,6 +4,7 @@ use crate::cal::abstract_gregorian::{impl_with_abstract_gregorian, GregorianYears}; use crate::calendar_arithmetic::ArithmeticDate; +use crate::error::UnknownEraError; use crate::preferences::CalendarAlgorithm; use crate::{types, Date, DateError, RangeError}; use tinystr::tinystr; @@ -40,12 +41,12 @@ pub(crate) struct RocEra; impl GregorianYears for RocEra { const EXTENDED_YEAR_OFFSET: i32 = 1911; - fn extended_from_era_year(&self, era: Option<&str>, year: i32) -> Result { + fn extended_from_era_year(&self, era: Option<&str>, year: i32) -> Result { match era { None => Ok(year), Some("roc") => Ok(year), Some("broc") => Ok(1 - year), - Some(_) => Err(DateError::UnknownEra), + Some(_) => Err(UnknownEraError), } } diff --git a/components/calendar/src/calendar.rs b/components/calendar/src/calendar.rs index 876c045b257..f13e72884f8 100644 --- a/components/calendar/src/calendar.rs +++ b/components/calendar/src/calendar.rs @@ -5,7 +5,7 @@ use calendrical_calculations::rata_die::RataDie; use crate::cal::iso::IsoDateInner; -use crate::error::DateError; +use crate::error::{DateError, DateFromFieldsError}; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::options::{DateFromFieldsOptions, MissingFieldsStrategy, Overflow}; use crate::types; @@ -60,7 +60,29 @@ pub trait Calendar: crate::cal::scaffold::UnstableSealed { overflow: Some(Overflow::Reject), missing_fields_strategy: Some(MissingFieldsStrategy::Reject), }; - self.from_fields(fields, options) + self.from_fields(fields, options).map_err(|e| match e { + // This error mapping is sufficiently bespoke to try_new_from_codes + // that it lives here and not in a From impl. + DateFromFieldsError::Range(range_error) => { + if range_error.field == "month" { + DateError::UnknownMonthCode(month_code) + } else { + range_error.into() + } + } + DateFromFieldsError::UnknownEra => DateError::UnknownEra, + DateFromFieldsError::InvalidMonthCode => DateError::UnknownMonthCode(month_code), + DateFromFieldsError::UnknownMonthCodeForCalendar => { + DateError::UnknownMonthCode(month_code) + } + DateFromFieldsError::UnknownMonthCodeForYear => DateError::UnknownMonthCode(month_code), + DateFromFieldsError::InconsistentYear + | DateFromFieldsError::InconsistentMonth + | DateFromFieldsError::NotEnoughFields => { + debug_assert!(false, "unreachable error in from_codes: {e}"); + DateError::UnknownEra + } + }) } /// Construct a date from a bag of date fields. @@ -69,7 +91,7 @@ pub trait Calendar: crate::cal::scaffold::UnstableSealed { &self, fields: types::DateFields, options: DateFromFieldsOptions, - ) -> Result; + ) -> Result; /// Construct the date from an ISO date #[expect(clippy::wrong_self_convention)] diff --git a/components/calendar/src/calendar_arithmetic.rs b/components/calendar/src/calendar_arithmetic.rs index 4492260d76e..84ced09ac8b 100644 --- a/components/calendar/src/calendar_arithmetic.rs +++ b/components/calendar/src/calendar_arithmetic.rs @@ -2,7 +2,10 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::error::{range_check, range_check_with_overflow}; +use crate::error::{ + range_check, range_check_with_overflow, DateFromFieldsError, EcmaReferenceYearError, + MonthCodeError, UnknownEraError, +}; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::options::{DateFromFieldsOptions, MissingFieldsStrategy, Overflow}; use crate::types::{DateDuration, DateDurationUnit, DateFields, DayOfYear, MonthCode}; @@ -147,7 +150,11 @@ pub(crate) trait DateFieldsResolver: Calendar { /// Converts the era and era year to a YearInfo. If the calendar does not have eras, /// this should always return an Err result. - fn year_info_from_era(&self, era: &str, era_year: i32) -> Result; + fn year_info_from_era( + &self, + era: &str, + era_year: i32, + ) -> Result; /// Converts an extended year to a YearInfo. fn year_info_from_extended(&self, extended_year: i32) -> Self::YearInfo; @@ -162,7 +169,7 @@ pub(crate) trait DateFieldsResolver: Calendar { &self, month_code: MonthCode, day: u8, - ) -> Result; + ) -> Result; /// Calculates the ordinal month for the given year and month code. /// @@ -173,10 +180,10 @@ pub(crate) trait DateFieldsResolver: Calendar { _year: &Self::YearInfo, month_code: MonthCode, _options: DateFromFieldsOptions, - ) -> Result { - match month_code.parsed() { - Some((month_number @ 1..=12, false)) => Ok(month_number), - _ => Err(DateError::UnknownMonthCode(month_code)), + ) -> Result { + match month_code.try_parse()? { + (month_number @ 1..=12, false) => Ok(month_number), + _ => Err(MonthCodeError::UnknownMonthCodeForCalendar), } } @@ -503,11 +510,26 @@ impl ArithmeticDate { let base_month_code = cal .month_code_from_ordinal(&self.year, self.month) .standard_code; - let m0 = cal.ordinal_month_from_code( - &y0, - base_month_code, - DateFromFieldsOptions::from_add_options(options), - )?; + let m0 = cal + .ordinal_month_from_code( + &y0, + base_month_code, + DateFromFieldsOptions::from_add_options(options), + ) + .map_err(|e| { + // TODO: Use a narrower error type here. For now, convert into DateError. + match e { + MonthCodeError::InvalidMonthCode => { + DateError::UnknownMonthCode(base_month_code) + } + MonthCodeError::UnknownMonthCodeForCalendar => { + DateError::UnknownMonthCode(base_month_code) + } + MonthCodeError::UnknownMonthCodeForYear => { + DateError::UnknownMonthCode(base_month_code) + } + } + })?; // 1. Let _endOfMonth_ be BalanceNonISODate(_calendar_, _y0_, _m0_ + _duration_.[[Months]] + 1, 0). let end_of_month = Self::new_balanced(y0, duration.add_months_to(m0) + 1, 0, cal); // 1. Let _baseDay_ be _parts_.[[Day]]. @@ -648,7 +670,7 @@ pub(crate) struct ArithmeticDateBuilder { fn extended_year_as_year_info( extended_year: i32, cal: &C, -) -> Result +) -> Result where C: DateFieldsResolver, { @@ -670,7 +692,7 @@ where fields: DateFields, cal: &C, options: DateFromFieldsOptions, - ) -> Result + ) -> Result where C: DateFieldsResolver, { @@ -679,14 +701,14 @@ where let day = match fields.day { Some(day) => day, None => match missing_fields_strategy { - MissingFieldsStrategy::Reject => return Err(DateError::NotEnoughFields), + MissingFieldsStrategy::Reject => return Err(DateFromFieldsError::NotEnoughFields), MissingFieldsStrategy::Ecma => { if fields.extended_year.is_some() || fields.era_year.is_some() { // The ECMAScript strategy is to pick day 1, always, regardless of whether // that day exists for the month/year combo 1 } else { - return Err(DateError::NotEnoughFields); + return Err(DateFromFieldsError::NotEnoughFields); } } }, @@ -695,7 +717,7 @@ where if fields.month_code.is_none() && fields.ordinal_month.is_none() { // We're returning this error early so that we return structural type // errors before range errors, see comment in the year code below. - return Err(DateError::NotEnoughFields); + return Err(DateFromFieldsError::NotEnoughFields); } let year = { @@ -711,13 +733,15 @@ where (None, None) => match fields.extended_year { Some(extended_year) => extended_year_as_year_info(extended_year, cal)?, None => match missing_fields_strategy { - MissingFieldsStrategy::Reject => return Err(DateError::NotEnoughFields), + MissingFieldsStrategy::Reject => { + return Err(DateFromFieldsError::NotEnoughFields) + } MissingFieldsStrategy::Ecma => { match (fields.month_code, fields.ordinal_month) { (Some(month_code), None) => { cal.reference_year_from_month_day(month_code, day)? } - _ => return Err(DateError::NotEnoughFields), + _ => return Err(DateFromFieldsError::NotEnoughFields), } } }, @@ -728,13 +752,15 @@ where if let Some(extended_year) = fields.extended_year { if era_year_as_year_info != extended_year_as_year_info(extended_year, cal)? { - return Err(DateError::InconsistentYear); + return Err(DateFromFieldsError::InconsistentYear); } } era_year_as_year_info } // Era and Era Year must be both or neither - (Some(_), None) | (None, Some(_)) => return Err(DateError::NotEnoughFields), + (Some(_), None) | (None, Some(_)) => { + return Err(DateFromFieldsError::NotEnoughFields) + } } }; @@ -744,7 +770,7 @@ where let computed_month = cal.ordinal_month_from_code(&year, month_code, options)?; if let Some(ordinal_month) = fields.ordinal_month { if computed_month != ordinal_month { - return Err(DateError::InconsistentMonth); + return Err(DateFromFieldsError::InconsistentMonth); } } computed_month @@ -753,7 +779,7 @@ where Some(month) => month, None => { debug_assert!(false, "Already checked above"); - return Err(DateError::NotEnoughFields); + return Err(DateFromFieldsError::NotEnoughFields); } }, } diff --git a/components/calendar/src/date.rs b/components/calendar/src/date.rs index 1147e4d3e42..cdbf917b96d 100644 --- a/components/calendar/src/date.rs +++ b/components/calendar/src/date.rs @@ -5,7 +5,7 @@ use crate::any_calendar::{AnyCalendar, IntoAnyCalendar}; use crate::cal::{abstract_gregorian::AbstractGregorian, iso::IsoEra}; use crate::calendar_arithmetic::CalendarArithmetic; -use crate::error::DateError; +use crate::error::{DateError, DateFromFieldsError}; use crate::options::DateFromFieldsOptions; use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::{CyclicYear, EraYear, IsoWeekOfYear}; @@ -150,7 +150,7 @@ impl Date { /// and fill in missing fields. See [`DateFromFieldsOptions`] for more information. /// /// This function will not accept year/extended_year values that are outside of the range `[-2²⁷, 2²⁷]`, - /// regardless of the calendar, instead returning a [`DateError::Range`]. This allows us to to keep + /// regardless of the calendar, instead returning a [`DateFromFieldsError::Range`]. This allows us to to keep /// all operations on [`Date`]s infallible by staying clear of integer limits. /// Currently, calendar-specific `Date::try_new_calendarname()` constructors /// do not do this, and it is possible to obtain such extreme dates via calendar conversion or arithmetic, @@ -160,7 +160,6 @@ impl Date { /// /// ``` /// use icu_calendar::Date; - /// use icu_calendar::DateError; /// use icu_calendar::cal::Gregorian; /// use icu_calendar::types::DateFields; /// @@ -180,13 +179,13 @@ impl Date { /// assert_eq!(d1, d2); /// ``` /// - /// See [`DateError`] for examples of error conditions. + /// See [`DateFromFieldsError`] for examples of error conditions. #[inline] pub fn try_from_fields( fields: types::DateFields, options: DateFromFieldsOptions, calendar: A, - ) -> Result { + ) -> Result { let inner = calendar.as_calendar().from_fields(fields, options)?; Ok(Date { inner, calendar }) } diff --git a/components/calendar/src/error.rs b/components/calendar/src/error.rs index 788d2660c59..f51e6c8f95d 100644 --- a/components/calendar/src/error.rs +++ b/components/calendar/src/error.rs @@ -2,11 +2,15 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +//! Error types for functions in the calendar crate + use crate::{options::Overflow, types::MonthCode}; use displaydoc::Display; #[derive(Debug, Copy, Clone, PartialEq, Display)] -/// Error type for date creation. +/// Error type for date creation via [`Date::try_new_from_codes`]. +/// +/// [`Date::try_new_from_codes`]: crate::Date::try_new_from_codes #[non_exhaustive] pub enum DateError { /// A field is out of range for its domain. @@ -59,13 +63,109 @@ pub enum DateError { /// ``` #[displaydoc("Unknown month code {0:?}")] UnknownMonthCode(MonthCode), +} + +impl core::error::Error for DateError {} + +/// Error type for date creation via [`Date::try_from_fields`]. +/// +/// [`Date::try_from_fields`]: crate::Date::try_from_fields +#[derive(Debug, Copy, Clone, PartialEq, Display)] +#[non_exhaustive] +pub enum DateFromFieldsError { + /// A field is out of range for its domain. + #[displaydoc("{0}")] + Range(RangeError), + /// The era code is invalid for the calendar. + #[displaydoc("Unknown era or invalid syntax")] + UnknownEra, + /// The month code syntax is invalid. + /// + /// # Examples + /// + /// ``` + /// use icu_calendar::Date; + /// use icu_calendar::error::DateFromFieldsError; + /// use icu_calendar::Iso; + /// use icu_calendar::types::MonthCode; + /// use icu_calendar::types::DateFields; + /// use tinystr::tinystr; + /// + /// let mut fields = DateFields::default(); + /// fields.extended_year = Some(2000); + /// fields.month_code = Some(MonthCode(tinystr!(4, "????"))); + /// fields.day = Some(1); + /// + /// let err = Date::try_from_fields( + /// fields, Default::default(), Iso + /// ) + /// .expect_err("month code is invalid"); + /// + /// assert!(matches!(err, DateFromFieldsError::InvalidMonthCode)); + /// ``` + #[displaydoc("Invalid month code syntax")] + InvalidMonthCode, + /// The specified month code does not exist in this calendar. + /// + /// # Examples + /// + /// ``` + /// use icu_calendar::Date; + /// use icu_calendar::error::DateFromFieldsError; + /// use icu_calendar::cal::Hebrew; + /// use icu_calendar::types::DateFields; + /// use icu_calendar::types::MonthCode; + /// use tinystr::tinystr; + /// + /// let mut fields = DateFields::default(); + /// fields.extended_year = Some(5783); + /// fields.month_code = Some(MonthCode::new_normal(13).unwrap()); + /// fields.day = Some(1); + /// + /// let err = Date::try_from_fields( + /// fields, + /// Default::default(), + /// Hebrew + /// ) + /// .expect_err("no month M13 in Hebrew"); + /// assert!(matches!(err, DateFromFieldsError::UnknownMonthCodeForCalendar)); + /// ``` + #[displaydoc("The specified month code does not exist in this calendar")] + UnknownMonthCodeForCalendar, + /// The specified month code exists in this calendar, but not in the specified year. + /// + /// # Examples + /// + /// ``` + /// use icu_calendar::Date; + /// use icu_calendar::error::DateFromFieldsError; + /// use icu_calendar::cal::Hebrew; + /// use icu_calendar::types::DateFields; + /// use icu_calendar::types::MonthCode; + /// use tinystr::tinystr; + /// + /// let mut fields = DateFields::default(); + /// fields.extended_year = Some(5783); + /// fields.month_code = Some(MonthCode::new_leap(5).unwrap()); + /// fields.day = Some(1); + /// + /// let err = Date::try_from_fields( + /// fields, + /// Default::default(), + /// Hebrew + /// ) + /// .expect_err("no month M05L in Hebrew year 5783"); + /// assert!(matches!(err, DateFromFieldsError::UnknownMonthCodeForYear)); + /// ``` + #[displaydoc("The specified month code exists in calendar, but not for this year")] + UnknownMonthCodeForYear, /// The year was specified in multiple inconsistent ways. /// /// # Examples /// /// ``` /// use icu_calendar::Date; - /// use icu_calendar::DateError; + /// use icu_calendar::error::DateFromFieldsError; /// use icu_calendar::cal::Japanese; /// use icu_calendar::types::DateFields; /// @@ -91,7 +191,7 @@ pub enum DateError { /// ) /// .expect_err("year 1900 is not the same as 6 Reiwa"); /// - /// assert!(matches!(err, DateError::InconsistentYear)); + /// assert!(matches!(err, DateFromFieldsError::InconsistentYear)); /// ``` #[displaydoc("Inconsistent year")] InconsistentYear, @@ -101,7 +201,7 @@ pub enum DateError { /// /// ``` /// use icu_calendar::Date; - /// use icu_calendar::DateError; + /// use icu_calendar::error::DateFromFieldsError; /// use icu_calendar::cal::Hebrew; /// use icu_calendar::types::DateFields; /// use icu_calendar::types::MonthCode; @@ -129,7 +229,7 @@ pub enum DateError { /// ) /// .expect_err("month M06 is not the 6th month in leap year 5784"); /// - /// assert!(matches!(err, DateError::InconsistentMonth)); + /// assert!(matches!(err, DateFromFieldsError::InconsistentMonth)); /// ``` #[displaydoc("Inconsistent month")] InconsistentMonth, @@ -139,7 +239,7 @@ pub enum DateError { /// /// ``` /// use icu_calendar::Date; - /// use icu_calendar::DateError; + /// use icu_calendar::error::DateFromFieldsError; /// use icu_calendar::cal::Hebrew; /// use icu_calendar::types::DateFields; /// use icu_calendar::types::MonthCode; @@ -155,7 +255,7 @@ pub enum DateError { /// Hebrew /// ) /// .expect_err("need more than just an ordinal month"); - /// assert!(matches!(err, DateError::NotEnoughFields)); + /// assert!(matches!(err, DateFromFieldsError::NotEnoughFields)); /// /// fields.era_year = Some(5783); /// @@ -165,7 +265,7 @@ pub enum DateError { /// Hebrew /// ) /// .expect_err("need more than an ordinal month and an era year"); - /// assert!(matches!(err, DateError::NotEnoughFields)); + /// assert!(matches!(err, DateFromFieldsError::NotEnoughFields)); /// /// fields.extended_year = Some(5783); /// @@ -175,7 +275,7 @@ pub enum DateError { /// Hebrew /// ) /// .expect_err("era year still needs an era"); - /// assert!(matches!(err, DateError::NotEnoughFields)); + /// assert!(matches!(err, DateFromFieldsError::NotEnoughFields)); /// /// fields.era = Some("am"); /// @@ -185,7 +285,7 @@ pub enum DateError { /// Hebrew /// ) /// .expect_err("still missing the day"); - /// assert!(matches!(err, DateError::NotEnoughFields)); + /// assert!(matches!(err, DateFromFieldsError::NotEnoughFields)); /// /// fields.day = Some(1); /// let date = Date::try_from_fields( @@ -199,7 +299,106 @@ pub enum DateError { NotEnoughFields, } -impl core::error::Error for DateError {} +impl core::error::Error for DateFromFieldsError {} + +impl From for DateFromFieldsError { + #[inline] + fn from(value: RangeError) -> Self { + DateFromFieldsError::Range(value) + } +} + +/// Internal narrow error type for functions that only fail on unknown eras +pub(crate) struct UnknownEraError; + +impl From for DateError { + #[inline] + fn from(_value: UnknownEraError) -> Self { + DateError::UnknownEra + } +} + +impl From for DateFromFieldsError { + #[inline] + fn from(_value: UnknownEraError) -> Self { + DateFromFieldsError::UnknownEra + } +} + +/// Internal narrow error type for functions that only fail on invalid month codes +pub(crate) enum MonthCodeParseError { + InvalidMonthCode, +} + +impl From for EcmaReferenceYearError { + #[inline] + fn from(value: MonthCodeParseError) -> Self { + match value { + MonthCodeParseError::InvalidMonthCode => EcmaReferenceYearError::InvalidMonthCode, + } + } +} + +impl From for MonthCodeError { + #[inline] + fn from(value: MonthCodeParseError) -> Self { + match value { + MonthCodeParseError::InvalidMonthCode => MonthCodeError::InvalidMonthCode, + } + } +} + +/// Internal narrow error type for functions that only fail on month code operations +pub(crate) enum MonthCodeError { + InvalidMonthCode, + UnknownMonthCodeForCalendar, + UnknownMonthCodeForYear, +} + +impl From for DateFromFieldsError { + #[inline] + fn from(value: MonthCodeError) -> Self { + match value { + MonthCodeError::InvalidMonthCode => DateFromFieldsError::InvalidMonthCode, + MonthCodeError::UnknownMonthCodeForCalendar => { + DateFromFieldsError::UnknownMonthCodeForCalendar + } + MonthCodeError::UnknownMonthCodeForYear => DateFromFieldsError::UnknownMonthCodeForYear, + } + } +} + +mod inner { + /// Internal narrow error type for calculating the ECMA reference year + /// + /// Public but unstable because it is used on hijri::Rules + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[allow(missing_docs)] // TODO: fix when graduating + #[non_exhaustive] + pub enum EcmaReferenceYearError { + InvalidMonthCode, + UnknownMonthCodeForCalendar, + NotEnoughFields, + } +} + +#[cfg(feature = "unstable")] +pub use inner::EcmaReferenceYearError; +#[cfg(not(feature = "unstable"))] +pub(crate) use inner::EcmaReferenceYearError; + +impl From for DateFromFieldsError { + #[inline] + fn from(value: EcmaReferenceYearError) -> Self { + match value { + EcmaReferenceYearError::InvalidMonthCode => DateFromFieldsError::InvalidMonthCode, + EcmaReferenceYearError::UnknownMonthCodeForCalendar => { + DateFromFieldsError::UnknownMonthCodeForCalendar + } + EcmaReferenceYearError::NotEnoughFields => DateFromFieldsError::NotEnoughFields, + } + } +} #[derive(Debug, Copy, Clone, PartialEq, Display)] /// An argument is out of range for its domain. @@ -216,18 +415,6 @@ pub struct RangeError { pub max: i32, } -impl RangeError { - #[inline] - pub(crate) fn maybe_with_month_code(self, month_code: Option) -> DateError { - if let Some(month_code) = month_code { - if self.field == "month" { - return DateError::UnknownMonthCode(month_code); - } - } - self.into() - } -} - impl core::error::Error for RangeError {} impl From for DateError { diff --git a/components/calendar/src/lib.rs b/components/calendar/src/lib.rs index 3854a662174..ab227553e0c 100644 --- a/components/calendar/src/lib.rs +++ b/components/calendar/src/lib.rs @@ -106,7 +106,7 @@ pub mod week; mod calendar; mod calendar_arithmetic; mod duration; -mod error; +pub mod error; #[cfg(feature = "ixdtf")] mod ixdtf; diff --git a/components/calendar/src/options.rs b/components/calendar/src/options.rs index 0445c96a94a..9ab1c17e1ad 100644 --- a/components/calendar/src/options.rs +++ b/components/calendar/src/options.rs @@ -278,7 +278,7 @@ pub enum Overflow { /// /// ``` /// use icu_calendar::Date; - /// use icu_calendar::DateError; + /// use icu_calendar::error::DateFromFieldsError; /// use icu_calendar::cal::Hebrew; /// use icu_calendar::options::DateFromFieldsOptions; /// use icu_calendar::options::Overflow; @@ -301,7 +301,7 @@ pub enum Overflow { /// Hebrew /// ) /// .expect_err("Day is out of bounds"); - /// assert!(matches!(err, DateError::Range { .. })); + /// assert!(matches!(err, DateFromFieldsError::Range { .. })); /// /// // Set the day to one that exists /// fields.day = Some(1); @@ -320,7 +320,7 @@ pub enum Overflow { /// Hebrew /// ) /// .expect_err("Month is out of bounds"); - /// assert!(matches!(err, DateError::UnknownMonthCode(_))); + /// assert!(matches!(err, DateFromFieldsError::UnknownMonthCodeForYear)); /// ``` #[default] Reject, @@ -360,9 +360,9 @@ pub enum Overflow { #[non_exhaustive] pub enum MissingFieldsStrategy { /// If the fields that are present do not fully constitute a Date, - /// return [`DateError::NotEnoughFields`]. + /// return [`DateFromFieldsError::NotEnoughFields`]. /// - /// [`DateError::NotEnoughFields`]: crate::DateError::NotEnoughFields + /// [`DateFromFieldsError::NotEnoughFields`]: crate::error::DateFromFieldsError::NotEnoughFields #[default] Reject, /// If the fields that are present do not fully constitute a Date, @@ -385,8 +385,9 @@ pub enum MissingFieldsStrategy { #[cfg(test)] mod tests { use crate::{ + error::DateFromFieldsError, types::{DateFields, MonthCode}, - Date, DateError, Gregorian, + Date, Gregorian, }; use itertools::Itertools; use std::collections::{BTreeMap, BTreeSet}; @@ -493,7 +494,7 @@ mod tests { should_succeed_rejecting, "Succeeded, but should have rejected: {fields:?}" ), - Err(DateError::NotEnoughFields) => assert!( + Err(DateFromFieldsError::NotEnoughFields) => assert!( !should_succeed_rejecting, "Rejected, but should have succeeded: {fields:?}" ), @@ -508,7 +509,7 @@ mod tests { should_succeed_ecma, "Succeeded, but should have rejected (ECMA): {fields:?}" ), - Err(DateError::NotEnoughFields) => assert!( + Err(DateFromFieldsError::NotEnoughFields) => assert!( !should_succeed_ecma, "Rejected, but should have succeeded (ECMA): {fields:?}" ), diff --git a/components/calendar/src/tests/not_enough_fields.rs b/components/calendar/src/tests/not_enough_fields.rs index ce365a29b2d..f8df5e74a79 100644 --- a/components/calendar/src/tests/not_enough_fields.rs +++ b/components/calendar/src/tests/not_enough_fields.rs @@ -2,10 +2,10 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use crate::error::DateFromFieldsError; use crate::options::{DateFromFieldsOptions, MissingFieldsStrategy, Overflow}; use crate::types::{DateFields, MonthCode}; use crate::Date; -use crate::DateError; #[test] fn test_from_fields_not_enough_fields() { @@ -44,7 +44,7 @@ fn test_from_fields_not_enough_fields() { options, calendar ), - Err(DateError::NotEnoughFields), + Err(DateFromFieldsError::NotEnoughFields), "Test with {options:?}" ); assert_eq!( @@ -60,7 +60,7 @@ fn test_from_fields_not_enough_fields() { options, calendar ), - Err(DateError::NotEnoughFields), + Err(DateFromFieldsError::NotEnoughFields), "Test with {options:?}" ); assert_eq!( @@ -76,7 +76,7 @@ fn test_from_fields_not_enough_fields() { options, calendar ), - Err(DateError::NotEnoughFields), + Err(DateFromFieldsError::NotEnoughFields), "Test with {options:?}" ); @@ -94,7 +94,7 @@ fn test_from_fields_not_enough_fields() { options, calendar ), - Err(DateError::NotEnoughFields), + Err(DateFromFieldsError::NotEnoughFields), "Test with {options:?}" ); assert_eq!( @@ -110,7 +110,7 @@ fn test_from_fields_not_enough_fields() { options, calendar ), - Err(DateError::NotEnoughFields), + Err(DateFromFieldsError::NotEnoughFields), "Test with {options:?}" ); @@ -128,7 +128,7 @@ fn test_from_fields_not_enough_fields() { options, calendar ), - Err(DateError::NotEnoughFields), + Err(DateFromFieldsError::NotEnoughFields), "Test with {options:?}" ); assert_eq!( @@ -144,7 +144,7 @@ fn test_from_fields_not_enough_fields() { options, calendar ), - Err(DateError::NotEnoughFields), + Err(DateFromFieldsError::NotEnoughFields), "Test with {options:?}" ); if missing_fields != MissingFieldsStrategy::Ecma { @@ -162,7 +162,7 @@ fn test_from_fields_not_enough_fields() { options, calendar ), - Err(DateError::NotEnoughFields), + Err(DateFromFieldsError::NotEnoughFields), "Test with {options:?}" ); assert_eq!( @@ -178,7 +178,7 @@ fn test_from_fields_not_enough_fields() { options, calendar ), - Err(DateError::NotEnoughFields), + Err(DateFromFieldsError::NotEnoughFields), "Test with {options:?}" ); @@ -196,7 +196,7 @@ fn test_from_fields_not_enough_fields() { options, calendar ), - Err(DateError::NotEnoughFields), + Err(DateFromFieldsError::NotEnoughFields), "Test with {options:?}" ); assert_eq!( @@ -212,7 +212,7 @@ fn test_from_fields_not_enough_fields() { options, calendar ), - Err(DateError::NotEnoughFields), + Err(DateFromFieldsError::NotEnoughFields), "Test with {options:?}" ); assert_eq!( @@ -228,7 +228,7 @@ fn test_from_fields_not_enough_fields() { options, calendar ), - Err(DateError::NotEnoughFields), + Err(DateFromFieldsError::NotEnoughFields), "Test with {options:?}" ); } diff --git a/components/calendar/src/types.rs b/components/calendar/src/types.rs index eb4d975165c..e79f6d89b20 100644 --- a/components/calendar/src/types.rs +++ b/components/calendar/src/types.rs @@ -14,6 +14,7 @@ use zerovec::ule::AsULE; // Export the duration types from here #[doc(hidden)] // unstable pub use crate::duration::{DateDuration, DateDurationUnit}; +use crate::error::MonthCodeParseError; /// A bag of various ways of expressing the year, month, and/or day. /// @@ -186,22 +187,23 @@ impl MonthCode { } /// Get the month number and whether or not it is leap from the month code pub fn parsed(self) -> Option<(u8, bool)> { + self.try_parse().ok() + } + pub(crate) fn try_parse(self) -> Result<(u8, bool), MonthCodeParseError> { // Match statements on tinystrs are annoying so instead // we calculate it from the bytes directly let bytes = self.0.all_bytes(); let is_leap = bytes[3] == b'L'; if bytes[0] != b'M' { - return None; + return Err(MonthCodeParseError::InvalidMonthCode); } - if bytes[1] == b'0' { - if bytes[2] >= b'1' && bytes[2] <= b'9' { - return Some((bytes[2] - b'0', is_leap)); - } - } else if bytes[1] == b'1' && bytes[2] >= b'0' && bytes[2] <= b'3' { - return Some((10 + bytes[2] - b'0', is_leap)); + let b1 = bytes[1]; + let b2 = bytes[2]; + if !b1.is_ascii_digit() || !b2.is_ascii_digit() { + return Err(MonthCodeParseError::InvalidMonthCode); } - None + Ok(((b1 - b'0') * 10 + b2 - b'0', is_leap)) } /// Construct a "normal" month code given a number ("Mxx"). diff --git a/components/calendar/tests/reference_year.rs b/components/calendar/tests/reference_year.rs index 2bad5105695..a9566fe3721 100644 --- a/components/calendar/tests/reference_year.rs +++ b/components/calendar/tests/reference_year.rs @@ -6,9 +6,10 @@ use std::{collections::HashSet, fmt::Debug}; use icu_calendar::{ cal::*, + error::DateFromFieldsError, options::{DateFromFieldsOptions, MissingFieldsStrategy, Overflow}, types::{DateFields, MonthCode}, - Calendar, Date, DateError, Ref, + Calendar, Date, Ref, }; /// Test that a given calendar produces valid monthdays @@ -65,7 +66,7 @@ where ); d } - Err(DateError::UnknownMonthCode(_)) => { + Err(DateFromFieldsError::UnknownMonthCodeForCalendar) => { assert!( !is_valid_month, "try_from_fields failed but should have passed: {fields:?}" @@ -95,13 +96,19 @@ where if valid_day_number == day_number { assert_eq!(reject_result, Ok(reference_date)); } else { - assert!(matches!(reject_result, Err(DateError::Range { .. }))) + assert!(matches!( + reject_result, + Err(DateFromFieldsError::Range { .. }) + )) } // Test that ordinal months cause it to fail (even if the month code is still set) fields.ordinal_month = Some(month_number); let ordinal_result = Date::try_from_fields(fields, options, Ref(&cal)); - assert!(matches!(ordinal_result, Err(DateError::NotEnoughFields))); + assert!(matches!( + ordinal_result, + Err(DateFromFieldsError::NotEnoughFields) + )); } } } diff --git a/ffi/capi/bindings/c/CalendarDateFromFieldsError.d.h b/ffi/capi/bindings/c/CalendarDateFromFieldsError.d.h new file mode 100644 index 00000000000..581fee84b2a --- /dev/null +++ b/ffi/capi/bindings/c/CalendarDateFromFieldsError.d.h @@ -0,0 +1,30 @@ +#ifndef CalendarDateFromFieldsError_D_H +#define CalendarDateFromFieldsError_D_H + +#include +#include +#include +#include +#include "diplomat_runtime.h" + + + + + +typedef enum CalendarDateFromFieldsError { + CalendarDateFromFieldsError_Unknown = 0, + CalendarDateFromFieldsError_OutOfRange = 1, + CalendarDateFromFieldsError_UnknownEra = 2, + CalendarDateFromFieldsError_InvalidMonthCode = 3, + CalendarDateFromFieldsError_UnknownMonthCodeForCalendar = 4, + CalendarDateFromFieldsError_UnknownMonthCodeForYear = 5, + CalendarDateFromFieldsError_InconsistentYear = 6, + CalendarDateFromFieldsError_InconsistentMonth = 7, + CalendarDateFromFieldsError_NotEnoughFields = 8, +} CalendarDateFromFieldsError; + +typedef struct CalendarDateFromFieldsError_option {union { CalendarDateFromFieldsError ok; }; bool is_ok; } CalendarDateFromFieldsError_option; + + + +#endif // CalendarDateFromFieldsError_D_H diff --git a/ffi/capi/bindings/c/CalendarDateFromFieldsError.h b/ffi/capi/bindings/c/CalendarDateFromFieldsError.h new file mode 100644 index 00000000000..c085e92da61 --- /dev/null +++ b/ffi/capi/bindings/c/CalendarDateFromFieldsError.h @@ -0,0 +1,22 @@ +#ifndef CalendarDateFromFieldsError_H +#define CalendarDateFromFieldsError_H + +#include +#include +#include +#include +#include "diplomat_runtime.h" + + +#include "CalendarDateFromFieldsError.d.h" + + + + +// No Content + + + + + +#endif // CalendarDateFromFieldsError_H diff --git a/ffi/capi/bindings/c/Date.h b/ffi/capi/bindings/c/Date.h index 1ce4f630180..4ed92657066 100644 --- a/ffi/capi/bindings/c/Date.h +++ b/ffi/capi/bindings/c/Date.h @@ -8,6 +8,7 @@ #include "diplomat_runtime.h" #include "Calendar.d.h" +#include "CalendarDateFromFieldsError.d.h" #include "CalendarError.d.h" #include "DateFields.d.h" #include "DateFromFieldsOptions.d.h" @@ -25,7 +26,7 @@ typedef struct icu4x_Date_from_iso_in_calendar_mv1_result {union {Date* ok; CalendarError err;}; bool is_ok;} icu4x_Date_from_iso_in_calendar_mv1_result; icu4x_Date_from_iso_in_calendar_mv1_result icu4x_Date_from_iso_in_calendar_mv1(int32_t iso_year, uint8_t iso_month, uint8_t iso_day, const Calendar* calendar); -typedef struct icu4x_Date_from_fields_in_calendar_mv1_result {union {Date* ok; CalendarError err;}; bool is_ok;} icu4x_Date_from_fields_in_calendar_mv1_result; +typedef struct icu4x_Date_from_fields_in_calendar_mv1_result {union {Date* ok; CalendarDateFromFieldsError err;}; bool is_ok;} icu4x_Date_from_fields_in_calendar_mv1_result; icu4x_Date_from_fields_in_calendar_mv1_result icu4x_Date_from_fields_in_calendar_mv1(DateFields fields, DateFromFieldsOptions options, const Calendar* calendar); typedef struct icu4x_Date_from_codes_in_calendar_mv1_result {union {Date* ok; CalendarError err;}; bool is_ok;} icu4x_Date_from_codes_in_calendar_mv1_result; diff --git a/ffi/capi/bindings/cpp/icu4x/CalendarDateFromFieldsError.d.hpp b/ffi/capi/bindings/cpp/icu4x/CalendarDateFromFieldsError.d.hpp new file mode 100644 index 00000000000..d4064b6b833 --- /dev/null +++ b/ffi/capi/bindings/cpp/icu4x/CalendarDateFromFieldsError.d.hpp @@ -0,0 +1,66 @@ +#ifndef ICU4X_CalendarDateFromFieldsError_D_HPP +#define ICU4X_CalendarDateFromFieldsError_D_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include "diplomat_runtime.hpp" + + +namespace icu4x { +namespace capi { + enum CalendarDateFromFieldsError { + CalendarDateFromFieldsError_Unknown = 0, + CalendarDateFromFieldsError_OutOfRange = 1, + CalendarDateFromFieldsError_UnknownEra = 2, + CalendarDateFromFieldsError_InvalidMonthCode = 3, + CalendarDateFromFieldsError_UnknownMonthCodeForCalendar = 4, + CalendarDateFromFieldsError_UnknownMonthCodeForYear = 5, + CalendarDateFromFieldsError_InconsistentYear = 6, + CalendarDateFromFieldsError_InconsistentMonth = 7, + CalendarDateFromFieldsError_NotEnoughFields = 8, + }; + + typedef struct CalendarDateFromFieldsError_option {union { CalendarDateFromFieldsError ok; }; bool is_ok; } CalendarDateFromFieldsError_option; +} // namespace capi +} // namespace + +namespace icu4x { +/** + * Additional information: [1](https://docs.rs/icu/2.0.0/icu/calendar/error/enum.DateFromFieldsError.html) + */ +class CalendarDateFromFieldsError { +public: + enum Value { + Unknown = 0, + OutOfRange = 1, + UnknownEra = 2, + InvalidMonthCode = 3, + UnknownMonthCodeForCalendar = 4, + UnknownMonthCodeForYear = 5, + InconsistentYear = 6, + InconsistentMonth = 7, + NotEnoughFields = 8, + }; + + CalendarDateFromFieldsError(): value(Value::Unknown) {} + + // Implicit conversions between enum and ::Value + constexpr CalendarDateFromFieldsError(Value v) : value(v) {} + constexpr operator Value() const { return value; } + // Prevent usage as boolean value + explicit operator bool() const = delete; + + inline icu4x::capi::CalendarDateFromFieldsError AsFFI() const; + inline static icu4x::CalendarDateFromFieldsError FromFFI(icu4x::capi::CalendarDateFromFieldsError c_enum); +private: + Value value; +}; + +} // namespace +#endif // ICU4X_CalendarDateFromFieldsError_D_HPP diff --git a/ffi/capi/bindings/cpp/icu4x/CalendarDateFromFieldsError.hpp b/ffi/capi/bindings/cpp/icu4x/CalendarDateFromFieldsError.hpp new file mode 100644 index 00000000000..38d25f8e800 --- /dev/null +++ b/ffi/capi/bindings/cpp/icu4x/CalendarDateFromFieldsError.hpp @@ -0,0 +1,43 @@ +#ifndef ICU4X_CalendarDateFromFieldsError_HPP +#define ICU4X_CalendarDateFromFieldsError_HPP + +#include "CalendarDateFromFieldsError.d.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "diplomat_runtime.hpp" + + +namespace icu4x { +namespace capi { + +} // namespace capi +} // namespace + +inline icu4x::capi::CalendarDateFromFieldsError icu4x::CalendarDateFromFieldsError::AsFFI() const { + return static_cast(value); +} + +inline icu4x::CalendarDateFromFieldsError icu4x::CalendarDateFromFieldsError::FromFFI(icu4x::capi::CalendarDateFromFieldsError c_enum) { + switch (c_enum) { + case icu4x::capi::CalendarDateFromFieldsError_Unknown: + case icu4x::capi::CalendarDateFromFieldsError_OutOfRange: + case icu4x::capi::CalendarDateFromFieldsError_UnknownEra: + case icu4x::capi::CalendarDateFromFieldsError_InvalidMonthCode: + case icu4x::capi::CalendarDateFromFieldsError_UnknownMonthCodeForCalendar: + case icu4x::capi::CalendarDateFromFieldsError_UnknownMonthCodeForYear: + case icu4x::capi::CalendarDateFromFieldsError_InconsistentYear: + case icu4x::capi::CalendarDateFromFieldsError_InconsistentMonth: + case icu4x::capi::CalendarDateFromFieldsError_NotEnoughFields: + return static_cast(c_enum); + default: + std::abort(); + } +} +#endif // ICU4X_CalendarDateFromFieldsError_HPP diff --git a/ffi/capi/bindings/cpp/icu4x/Date.d.hpp b/ffi/capi/bindings/cpp/icu4x/Date.d.hpp index 5716a5d7339..a932a7bb5bb 100644 --- a/ffi/capi/bindings/cpp/icu4x/Date.d.hpp +++ b/ffi/capi/bindings/cpp/icu4x/Date.d.hpp @@ -19,6 +19,7 @@ namespace capi { struct IsoDate; } class IsoDate; struct DateFields; struct DateFromFieldsOptions; +class CalendarDateFromFieldsError; class CalendarError; class Rfc9557ParseError; class Weekday; @@ -54,7 +55,7 @@ class Date { * * See the [Rust documentation for `try_from_fields`](https://docs.rs/icu/2.0.0/icu/calendar/struct.Date.html#method.try_from_fields) for more information. */ - inline static icu4x::diplomat::result, icu4x::CalendarError> from_fields_in_calendar(icu4x::DateFields fields, icu4x::DateFromFieldsOptions options, const icu4x::Calendar& calendar); + inline static icu4x::diplomat::result, icu4x::CalendarDateFromFieldsError> from_fields_in_calendar(icu4x::DateFields fields, icu4x::DateFromFieldsOptions options, const icu4x::Calendar& calendar); /** * Creates a new {@link Date} from the given codes, which are interpreted in the given calendar system diff --git a/ffi/capi/bindings/cpp/icu4x/Date.hpp b/ffi/capi/bindings/cpp/icu4x/Date.hpp index 03e21acd777..46e392c311a 100644 --- a/ffi/capi/bindings/cpp/icu4x/Date.hpp +++ b/ffi/capi/bindings/cpp/icu4x/Date.hpp @@ -12,6 +12,7 @@ #include #include #include "Calendar.hpp" +#include "CalendarDateFromFieldsError.hpp" #include "CalendarError.hpp" #include "DateFields.hpp" #include "DateFromFieldsOptions.hpp" @@ -28,7 +29,7 @@ namespace capi { typedef struct icu4x_Date_from_iso_in_calendar_mv1_result {union {icu4x::capi::Date* ok; icu4x::capi::CalendarError err;}; bool is_ok;} icu4x_Date_from_iso_in_calendar_mv1_result; icu4x_Date_from_iso_in_calendar_mv1_result icu4x_Date_from_iso_in_calendar_mv1(int32_t iso_year, uint8_t iso_month, uint8_t iso_day, const icu4x::capi::Calendar* calendar); - typedef struct icu4x_Date_from_fields_in_calendar_mv1_result {union {icu4x::capi::Date* ok; icu4x::capi::CalendarError err;}; bool is_ok;} icu4x_Date_from_fields_in_calendar_mv1_result; + typedef struct icu4x_Date_from_fields_in_calendar_mv1_result {union {icu4x::capi::Date* ok; icu4x::capi::CalendarDateFromFieldsError err;}; bool is_ok;} icu4x_Date_from_fields_in_calendar_mv1_result; icu4x_Date_from_fields_in_calendar_mv1_result icu4x_Date_from_fields_in_calendar_mv1(icu4x::capi::DateFields fields, icu4x::capi::DateFromFieldsOptions options, const icu4x::capi::Calendar* calendar); typedef struct icu4x_Date_from_codes_in_calendar_mv1_result {union {icu4x::capi::Date* ok; icu4x::capi::CalendarError err;}; bool is_ok;} icu4x_Date_from_codes_in_calendar_mv1_result; @@ -88,11 +89,11 @@ inline icu4x::diplomat::result, icu4x::CalendarErro return result.is_ok ? icu4x::diplomat::result, icu4x::CalendarError>(icu4x::diplomat::Ok>(std::unique_ptr(icu4x::Date::FromFFI(result.ok)))) : icu4x::diplomat::result, icu4x::CalendarError>(icu4x::diplomat::Err(icu4x::CalendarError::FromFFI(result.err))); } -inline icu4x::diplomat::result, icu4x::CalendarError> icu4x::Date::from_fields_in_calendar(icu4x::DateFields fields, icu4x::DateFromFieldsOptions options, const icu4x::Calendar& calendar) { +inline icu4x::diplomat::result, icu4x::CalendarDateFromFieldsError> icu4x::Date::from_fields_in_calendar(icu4x::DateFields fields, icu4x::DateFromFieldsOptions options, const icu4x::Calendar& calendar) { auto result = icu4x::capi::icu4x_Date_from_fields_in_calendar_mv1(fields.AsFFI(), options.AsFFI(), calendar.AsFFI()); - return result.is_ok ? icu4x::diplomat::result, icu4x::CalendarError>(icu4x::diplomat::Ok>(std::unique_ptr(icu4x::Date::FromFFI(result.ok)))) : icu4x::diplomat::result, icu4x::CalendarError>(icu4x::diplomat::Err(icu4x::CalendarError::FromFFI(result.err))); + return result.is_ok ? icu4x::diplomat::result, icu4x::CalendarDateFromFieldsError>(icu4x::diplomat::Ok>(std::unique_ptr(icu4x::Date::FromFFI(result.ok)))) : icu4x::diplomat::result, icu4x::CalendarDateFromFieldsError>(icu4x::diplomat::Err(icu4x::CalendarDateFromFieldsError::FromFFI(result.err))); } inline icu4x::diplomat::result, icu4x::CalendarError> icu4x::Date::from_codes_in_calendar(std::string_view era_code, int32_t year, std::string_view month_code, uint8_t day, const icu4x::Calendar& calendar) { diff --git a/ffi/capi/bindings/dart/CalendarDateFromFieldsError.g.dart b/ffi/capi/bindings/dart/CalendarDateFromFieldsError.g.dart new file mode 100644 index 00000000000..e45fef193ee --- /dev/null +++ b/ffi/capi/bindings/dart/CalendarDateFromFieldsError.g.dart @@ -0,0 +1,29 @@ +// generated by diplomat-tool +// dart format off + +part of 'lib.g.dart'; + +/// Additional information: [1](https://docs.rs/icu/2.0.0/icu/calendar/error/enum.DateFromFieldsError.html) +enum CalendarDateFromFieldsError { + + unknown, + + outOfRange, + + unknownEra, + + invalidMonthCode, + + unknownMonthCodeForCalendar, + + unknownMonthCodeForYear, + + inconsistentYear, + + inconsistentMonth, + + notEnoughFields; + +} + +// dart format on diff --git a/ffi/capi/bindings/dart/Date.g.dart b/ffi/capi/bindings/dart/Date.g.dart index 0e7f5ecb40c..49727572bbc 100644 --- a/ffi/capi/bindings/dart/Date.g.dart +++ b/ffi/capi/bindings/dart/Date.g.dart @@ -44,12 +44,12 @@ final class Date implements ffi.Finalizable { /// /// See the [Rust documentation for `try_from_fields`](https://docs.rs/icu/2.0.0/icu/calendar/struct.Date.html#method.try_from_fields) for more information. /// - /// Throws [CalendarError] on failure. + /// Throws [CalendarDateFromFieldsError] on failure. factory Date.fromFieldsInCalendar(DateFields fields, DateFromFieldsOptions options, Calendar calendar) { final temp = _FinalizedArena(); final result = _icu4x_Date_from_fields_in_calendar_mv1(fields._toFfi(temp.arena), options._toFfi(temp.arena), calendar._ffi); if (!result.isOk) { - throw CalendarError.values[result.union.err]; + throw CalendarDateFromFieldsError.values[result.union.err]; } return Date._fromFfi(result.union.ok, []); } diff --git a/ffi/capi/bindings/dart/lib.g.dart b/ffi/capi/bindings/dart/lib.g.dart index ff40fbbd775..1de8b144cf8 100644 --- a/ffi/capi/bindings/dart/lib.g.dart +++ b/ffi/capi/bindings/dart/lib.g.dart @@ -19,6 +19,7 @@ part 'BidiMirroringGlyph.g.dart'; part 'BidiPairedBracketType.g.dart'; part 'BidiParagraph.g.dart'; part 'Calendar.g.dart'; +part 'CalendarDateFromFieldsError.g.dart'; part 'CalendarError.g.dart'; part 'CalendarKind.g.dart'; part 'CanonicalCombiningClass.g.dart'; diff --git a/ffi/capi/bindings/js/CalendarDateFromFieldsError.d.ts b/ffi/capi/bindings/js/CalendarDateFromFieldsError.d.ts new file mode 100644 index 00000000000..2ec0985c9cd --- /dev/null +++ b/ffi/capi/bindings/js/CalendarDateFromFieldsError.d.ts @@ -0,0 +1,31 @@ +// generated by diplomat-tool +import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; + + + +/** + * Additional information: [1](https://docs.rs/icu/2.0.0/icu/calendar/error/enum.DateFromFieldsError.html) + */ +export class CalendarDateFromFieldsError { + + /** @internal */ + static fromValue(value: CalendarDateFromFieldsError | string): CalendarDateFromFieldsError; + + get value(): string; + + /** @internal */ + get ffiValue(): number; + + static Unknown : CalendarDateFromFieldsError; + static OutOfRange : CalendarDateFromFieldsError; + static UnknownEra : CalendarDateFromFieldsError; + static InvalidMonthCode : CalendarDateFromFieldsError; + static UnknownMonthCodeForCalendar : CalendarDateFromFieldsError; + static UnknownMonthCodeForYear : CalendarDateFromFieldsError; + static InconsistentYear : CalendarDateFromFieldsError; + static InconsistentMonth : CalendarDateFromFieldsError; + static NotEnoughFields : CalendarDateFromFieldsError; + + + constructor(value: CalendarDateFromFieldsError | string ); +} \ No newline at end of file diff --git a/ffi/capi/bindings/js/CalendarDateFromFieldsError.mjs b/ffi/capi/bindings/js/CalendarDateFromFieldsError.mjs new file mode 100644 index 00000000000..913e2d8dfac --- /dev/null +++ b/ffi/capi/bindings/js/CalendarDateFromFieldsError.mjs @@ -0,0 +1,93 @@ +// generated by diplomat-tool +import wasm from "./diplomat-wasm.mjs"; +import * as diplomatRuntime from "./diplomat-runtime.mjs"; + + + +/** + * Additional information: [1](https://docs.rs/icu/2.0.0/icu/calendar/error/enum.DateFromFieldsError.html) + */ +export class CalendarDateFromFieldsError { + #value = undefined; + + static #values = new Map([ + ["Unknown", 0], + ["OutOfRange", 1], + ["UnknownEra", 2], + ["InvalidMonthCode", 3], + ["UnknownMonthCodeForCalendar", 4], + ["UnknownMonthCodeForYear", 5], + ["InconsistentYear", 6], + ["InconsistentMonth", 7], + ["NotEnoughFields", 8] + ]); + + static getAllEntries() { + return CalendarDateFromFieldsError.#values.entries(); + } + + #internalConstructor(value) { + if (arguments.length > 1 && arguments[0] === diplomatRuntime.internalConstructor) { + // We pass in two internalConstructor arguments to create *new* + // instances of this type, otherwise the enums are treated as singletons. + if (arguments[1] === diplomatRuntime.internalConstructor ) { + this.#value = arguments[2]; + return this; + } + return CalendarDateFromFieldsError.#objectValues[arguments[1]]; + } + + if (value instanceof CalendarDateFromFieldsError) { + return value; + } + + let intVal = CalendarDateFromFieldsError.#values.get(value); + + // Nullish check, checks for null or undefined + if (intVal != null) { + return CalendarDateFromFieldsError.#objectValues[intVal]; + } + + throw TypeError(value + " is not a CalendarDateFromFieldsError and does not correspond to any of its enumerator values."); + } + + /** @internal */ + static fromValue(value) { + return new CalendarDateFromFieldsError(value); + } + + get value(){ + return [...CalendarDateFromFieldsError.#values.keys()][this.#value]; + } + + /** @internal */ + get ffiValue(){ + return this.#value; + } + static #objectValues = [ + new CalendarDateFromFieldsError(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 0), + new CalendarDateFromFieldsError(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 1), + new CalendarDateFromFieldsError(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 2), + new CalendarDateFromFieldsError(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 3), + new CalendarDateFromFieldsError(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 4), + new CalendarDateFromFieldsError(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 5), + new CalendarDateFromFieldsError(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 6), + new CalendarDateFromFieldsError(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 7), + new CalendarDateFromFieldsError(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 8), + ]; + + static Unknown = CalendarDateFromFieldsError.#objectValues[0]; + static OutOfRange = CalendarDateFromFieldsError.#objectValues[1]; + static UnknownEra = CalendarDateFromFieldsError.#objectValues[2]; + static InvalidMonthCode = CalendarDateFromFieldsError.#objectValues[3]; + static UnknownMonthCodeForCalendar = CalendarDateFromFieldsError.#objectValues[4]; + static UnknownMonthCodeForYear = CalendarDateFromFieldsError.#objectValues[5]; + static InconsistentYear = CalendarDateFromFieldsError.#objectValues[6]; + static InconsistentMonth = CalendarDateFromFieldsError.#objectValues[7]; + static NotEnoughFields = CalendarDateFromFieldsError.#objectValues[8]; + + + constructor(value) { + return this.#internalConstructor(...arguments) + } +} \ No newline at end of file diff --git a/ffi/capi/bindings/js/Date.d.ts b/ffi/capi/bindings/js/Date.d.ts index 3a0d14e8b53..d079a9c2c7c 100644 --- a/ffi/capi/bindings/js/Date.d.ts +++ b/ffi/capi/bindings/js/Date.d.ts @@ -1,5 +1,6 @@ // generated by diplomat-tool import type { Calendar } from "./Calendar" +import type { CalendarDateFromFieldsError } from "./CalendarDateFromFieldsError" import type { CalendarError } from "./CalendarError" import type { DateFields } from "./DateFields" import type { DateFields_obj } from "./DateFields" diff --git a/ffi/capi/bindings/js/Date.mjs b/ffi/capi/bindings/js/Date.mjs index 5e77f81bb87..2b97ea822a6 100644 --- a/ffi/capi/bindings/js/Date.mjs +++ b/ffi/capi/bindings/js/Date.mjs @@ -1,5 +1,6 @@ // generated by diplomat-tool import { Calendar } from "./Calendar.mjs" +import { CalendarDateFromFieldsError } from "./CalendarDateFromFieldsError.mjs" import { CalendarError } from "./CalendarError.mjs" import { DateFields } from "./DateFields.mjs" import { DateFromFieldsOptions } from "./DateFromFieldsOptions.mjs" @@ -87,8 +88,8 @@ export class Date { try { if (!diplomatReceive.resultFlag) { - const cause = new CalendarError(diplomatRuntime.internalConstructor, diplomatRuntime.enumDiscriminant(wasm, diplomatReceive.buffer)); - throw new globalThis.Error('CalendarError.' + cause.value, { cause }); + const cause = new CalendarDateFromFieldsError(diplomatRuntime.internalConstructor, diplomatRuntime.enumDiscriminant(wasm, diplomatReceive.buffer)); + throw new globalThis.Error('CalendarDateFromFieldsError.' + cause.value, { cause }); } return new Date(diplomatRuntime.internalConstructor, diplomatRuntime.ptrRead(wasm, diplomatReceive.buffer), []); } diff --git a/ffi/capi/bindings/js/index.d.ts b/ffi/capi/bindings/js/index.d.ts index ccc9d876c24..cd417b55ee8 100644 --- a/ffi/capi/bindings/js/index.d.ts +++ b/ffi/capi/bindings/js/index.d.ts @@ -260,6 +260,8 @@ export { DisplayNamesStyle } from "./DisplayNamesStyle" export { LanguageDisplay } from "./LanguageDisplay" +export { CalendarDateFromFieldsError } from "./CalendarDateFromFieldsError" + export { CalendarError } from "./CalendarError" export { DataError } from "./DataError" diff --git a/ffi/capi/bindings/js/index.mjs b/ffi/capi/bindings/js/index.mjs index 6ef8bca282e..c86d10feaed 100644 --- a/ffi/capi/bindings/js/index.mjs +++ b/ffi/capi/bindings/js/index.mjs @@ -258,6 +258,8 @@ export { DisplayNamesStyle } from "./DisplayNamesStyle.mjs" export { LanguageDisplay } from "./LanguageDisplay.mjs" +export { CalendarDateFromFieldsError } from "./CalendarDateFromFieldsError.mjs" + export { CalendarError } from "./CalendarError.mjs" export { DataError } from "./DataError.mjs" diff --git a/ffi/capi/src/date.rs b/ffi/capi/src/date.rs index 6e8b3b22753..d47f3fd88c3 100644 --- a/ffi/capi/src/date.rs +++ b/ffi/capi/src/date.rs @@ -2,7 +2,7 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::unstable::errors::ffi::CalendarError; +use crate::unstable::errors::ffi::CalendarDateFromFieldsError; use ffi::IsoWeekOfYear; use tinystr::TinyAsciiStr; @@ -16,7 +16,9 @@ pub mod ffi { use icu_calendar::Iso; use crate::unstable::calendar::ffi::Calendar; - use crate::unstable::errors::ffi::{CalendarError, Rfc9557ParseError}; + use crate::unstable::errors::ffi::{ + CalendarDateFromFieldsError, CalendarError, Rfc9557ParseError, + }; use tinystr::TinyAsciiStr; @@ -239,7 +241,7 @@ pub mod ffi { fields: DateFields, options: DateFromFieldsOptions, calendar: &Calendar, - ) -> Result, CalendarError> { + ) -> Result, CalendarDateFromFieldsError> { let cal = calendar.0.clone(); Ok(Box::new(Date(icu_calendar::Date::try_from_fields( fields.try_into()?, @@ -489,12 +491,12 @@ impl From for icu_calendar::options::DateFromFieldsO } impl<'a> TryFrom> for icu_calendar::types::DateFields<'a> { - type Error = CalendarError; - fn try_from(other: ffi::DateFields<'a>) -> Result { + type Error = CalendarDateFromFieldsError; + fn try_from(other: ffi::DateFields<'a>) -> Result { let mut fields = Self::default(); if let Some(era) = other.era.into_option() { let Ok(s) = core::str::from_utf8(era) else { - return Err(CalendarError::UnknownEra); + return Err(CalendarDateFromFieldsError::UnknownEra); }; fields.era = Some(s); } @@ -502,7 +504,7 @@ impl<'a> TryFrom> for icu_calendar::types::DateFields<'a> { fields.extended_year = other.extended_year.into(); if let Some(month_code) = other.month_code.into_option() { let Ok(code) = TinyAsciiStr::try_from_utf8(month_code) else { - return Err(CalendarError::UnknownMonthCode); + return Err(CalendarDateFromFieldsError::InvalidMonthCode); }; fields.month_code = Some(icu_calendar::types::MonthCode(code)); } diff --git a/ffi/capi/src/errors.rs b/ffi/capi/src/errors.rs index caea843a891..2f87bde5066 100644 --- a/ffi/capi/src/errors.rs +++ b/ffi/capi/src/errors.rs @@ -70,6 +70,23 @@ pub mod ffi { UnknownMonthCode = 0x03, } + #[derive(Debug, PartialEq, Eq)] + #[repr(C)] + #[diplomat::rust_link(icu::calendar::error::DateFromFieldsError, Enum, compact)] + #[cfg(feature = "calendar")] + #[non_exhaustive] + pub enum CalendarDateFromFieldsError { + Unknown = 0x00, + OutOfRange = 0x01, + UnknownEra = 0x02, + InvalidMonthCode = 0x03, + UnknownMonthCodeForCalendar = 0x04, + UnknownMonthCodeForYear = 0x05, + InconsistentYear = 0x06, + InconsistentMonth = 0x07, + NotEnoughFields = 0x08, + } + #[derive(Debug, PartialEq, Eq)] #[repr(C)] #[diplomat::rust_link(icu::calendar::ParseError, Enum, compact)] @@ -179,6 +196,27 @@ impl From for CalendarError { } } +#[cfg(feature = "calendar")] +impl From for CalendarDateFromFieldsError { + fn from(e: icu_calendar::error::DateFromFieldsError) -> Self { + match e { + icu_calendar::error::DateFromFieldsError::Range(_) => Self::OutOfRange, + icu_calendar::error::DateFromFieldsError::UnknownEra => Self::UnknownEra, + icu_calendar::error::DateFromFieldsError::InvalidMonthCode => Self::InvalidMonthCode, + icu_calendar::error::DateFromFieldsError::UnknownMonthCodeForCalendar => { + Self::UnknownMonthCodeForCalendar + } + icu_calendar::error::DateFromFieldsError::UnknownMonthCodeForYear => { + Self::UnknownMonthCodeForYear + } + icu_calendar::error::DateFromFieldsError::InconsistentYear => Self::InconsistentYear, + icu_calendar::error::DateFromFieldsError::InconsistentMonth => Self::InconsistentMonth, + icu_calendar::error::DateFromFieldsError::NotEnoughFields => Self::NotEnoughFields, + _ => Self::Unknown, + } + } +} + #[cfg(feature = "calendar")] impl From for Rfc9557ParseError { fn from(e: icu_calendar::ParseError) -> Self { diff --git a/ffi/capi/tests/missing_apis.txt b/ffi/capi/tests/missing_apis.txt index 31b13ebdf60..35216baf89d 100644 --- a/ffi/capi/tests/missing_apis.txt +++ b/ffi/capi/tests/missing_apis.txt @@ -14,6 +14,7 @@ # Please check in with @Manishearth, @robertbastian, or @sffc if you have questions +icu::calendar::error::EcmaReferenceYearError#Enum icu::collator::CollatorBorrowed::compare_latin1#FnInStruct icu::collator::CollatorBorrowed::compare_latin1_utf16#FnInStruct icu::collator::CollatorBorrowed::write_sort_key_to#FnInStruct diff --git a/tools/make/diplomat-coverage/src/allowlist.rs b/tools/make/diplomat-coverage/src/allowlist.rs index ffcaf6be859..9195dff8e49 100644 --- a/tools/make/diplomat-coverage/src/allowlist.rs +++ b/tools/make/diplomat-coverage/src/allowlist.rs @@ -330,6 +330,8 @@ lazy_static::lazy_static! { // Reexported "icu::calendar::any_calendar::AnyCalendar", "icu::calendar::any_calendar::AnyCalendarKind", + "icu::calendar::error::DateError", + "icu::calendar::error::RangeError", "icu::casemap::titlecase::TitlecaseMapper", "icu::casemap::titlecase::TitlecaseMapperBorrowed", "icu::time::zone::IanaParser",