Skip to content

Commit 16590ed

Browse files
Cleanup Chinese code (#6436)
Currently almost all the code in `chinese_based.rs` is generic in `CB: ChineseBased`, so it will all be monomorhized twice. This reduces the generic to just a handful of methods. It also changes `CyclicYear::year`'s type from `NonZeroU8` to `u8`, as we don't use `NonZero` types for any other of our 1-based outputs.
1 parent a9101ef commit 16590ed

File tree

12 files changed

+883
-1063
lines changed

12 files changed

+883
-1063
lines changed

components/calendar/src/cal/chinese.rs

Lines changed: 51 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,22 @@
1212
//! .expect("Failed to initialize Chinese Date instance.");
1313
//!
1414
//! assert_eq!(chinese_date.cyclic_year().related_iso, 2023);
15-
//! assert_eq!(chinese_date.cyclic_year().year.get(), 40);
15+
//! assert_eq!(chinese_date.cyclic_year().year, 40);
1616
//! assert_eq!(chinese_date.month().ordinal, 6);
1717
//! assert_eq!(chinese_date.day_of_month().0, 6);
1818
//! ```
1919
20-
use crate::cal::chinese_based::{
21-
chinese_based_ordinal_lunar_month_from_code, ChineseBasedDateInner,
22-
ChineseBasedPrecomputedData, ChineseBasedWithDataLoading,
23-
};
20+
use crate::cal::chinese_based::{ChineseBasedPrecomputedData, ChineseBasedWithDataLoading};
2421
use crate::cal::iso::{Iso, IsoDateInner};
25-
use crate::calendar_arithmetic::CalendarArithmetic;
2622
use crate::calendar_arithmetic::PrecomputedDataSource;
23+
use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic};
2724
use crate::error::DateError;
2825
use crate::provider::chinese_based::CalendarChineseV1;
2926
use crate::AsCalendar;
3027
use crate::{types, Calendar, Date, DateDuration, DateDurationUnit};
3128
use calendrical_calculations::chinese_based::{self, ChineseBased};
3229
use calendrical_calculations::rata_die::RataDie;
3330
use core::cmp::Ordering;
34-
use core::num::NonZeroU8;
3531
use icu_provider::prelude::*;
3632

3733
/// The [Chinese Calendar](https://en.wikipedia.org/wiki/Chinese_calendar)
@@ -84,9 +80,7 @@ pub struct Chinese {
8480

8581
/// The inner date type used for representing [`Date`]s of [`Chinese`]. See [`Date`] and [`Chinese`] for more details.
8682
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
87-
pub struct ChineseDateInner(ChineseBasedDateInner<Chinese>);
88-
89-
type Inner = ChineseBasedDateInner<Chinese>;
83+
pub struct ChineseDateInner(ArithmeticDate<Chinese>);
9084

9185
// we want these impls without the `C: Copy/Clone` bounds
9286
impl Copy for ChineseDateInner {}
@@ -169,37 +163,44 @@ impl Calendar for Chinese {
169163
month_code: types::MonthCode,
170164
day: u8,
171165
) -> Result<Self::DateInner, DateError> {
166+
match era {
167+
None => {}
168+
_ => return Err(DateError::UnknownEra),
169+
}
170+
172171
let year = self.get_precomputed_data().load_or_compute_info(year);
173172

174-
let Some(month) = chinese_based_ordinal_lunar_month_from_code(month_code, year) else {
173+
let Some(month) = year.parse_month_code(month_code) else {
175174
return Err(DateError::UnknownMonthCode(month_code));
176175
};
177176

178-
match era {
179-
None => {}
180-
_ => return Err(DateError::UnknownEra),
181-
}
177+
year.validate_md(month, day)?;
182178

183-
Inner::new_from_ordinals(year, month, day)
184-
.map(ChineseBasedDateInner)
185-
.map(ChineseDateInner)
179+
Ok(ChineseDateInner(ArithmeticDate::new_unchecked(
180+
year, month, day,
181+
)))
186182
}
187183

188184
fn from_rata_die(&self, rd: RataDie) -> Self::DateInner {
189185
let iso = Iso.from_rata_die(rd);
190-
ChineseDateInner(Inner::chinese_based_date_from_rd(self, rd, iso.0))
186+
let y = self
187+
.get_precomputed_data()
188+
.load_or_compute_info_for_rd(rd, iso.0);
189+
let (m, d) = y.md_from_rd(rd);
190+
ChineseDateInner(ArithmeticDate::new_unchecked(y, m, d))
191191
}
192192

193193
fn to_rata_die(&self, date: &Self::DateInner) -> RataDie {
194-
Inner::rd_from_chinese_based_date_inner(date.0)
194+
date.0.year.rd_from_md(date.0.month, date.0.day)
195195
}
196196

197197
fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner {
198-
ChineseDateInner(Inner::chinese_based_date_from_rd(
199-
self,
200-
Iso.to_rata_die(&iso),
201-
iso.0,
202-
))
198+
let rd = Iso.to_rata_die(&iso);
199+
let y = self
200+
.get_precomputed_data()
201+
.load_or_compute_info_for_rd(rd, iso.0);
202+
let (m, d) = y.md_from_rd(rd);
203+
ChineseDateInner(ArithmeticDate::new_unchecked(y, m, d))
203204
}
204205

205206
fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner {
@@ -209,16 +210,16 @@ impl Calendar for Chinese {
209210
// Count the number of months in a given year, specified by providing a date
210211
// from that year
211212
fn days_in_year(&self, date: &Self::DateInner) -> u16 {
212-
date.0.days_in_year_inner()
213+
date.0.days_in_year()
213214
}
214215

215216
fn days_in_month(&self, date: &Self::DateInner) -> u8 {
216-
date.0.days_in_month_inner()
217+
date.0.days_in_month()
217218
}
218219

219220
#[doc(hidden)] // unstable
220221
fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration<Self>) {
221-
date.0 .0.offset_date(offset, &self.get_precomputed_data());
222+
date.0.offset_date(offset, &self.get_precomputed_data());
222223
}
223224

224225
#[doc(hidden)] // unstable
@@ -235,7 +236,7 @@ impl Calendar for Chinese {
235236
_largest_unit: DateDurationUnit,
236237
_smallest_unit: DateDurationUnit,
237238
) -> DateDuration<Self> {
238-
date1.0 .0.until(date2.0 .0, _largest_unit, _smallest_unit)
239+
date1.0.until(date2.0, _largest_unit, _smallest_unit)
239240
}
240241

241242
/// Obtain a name for the calendar for debug printing
@@ -244,47 +245,45 @@ impl Calendar for Chinese {
244245
}
245246

246247
fn year_info(&self, date: &Self::DateInner) -> Self::Year {
247-
let year = date.0 .0.year;
248-
let cyclic = (year.related_iso - 4).rem_euclid(60) as u8;
249-
let cyclic = NonZeroU8::new(cyclic + 1).unwrap_or(NonZeroU8::MIN); // 1-indexed
248+
let year = date.0.year;
250249
types::CyclicYear {
251-
year: cyclic,
250+
year: (year.related_iso - 4).rem_euclid(60) as u8 + 1,
252251
related_iso: year.related_iso,
253252
}
254253
}
255254

256255
fn extended_year(&self, date: &Self::DateInner) -> i32 {
257-
chinese_based::Chinese::extended_from_iso(date.0 .0.year.related_iso)
256+
chinese_based::Chinese::extended_from_iso(date.0.year.related_iso)
258257
}
259258

260259
fn is_in_leap_year(&self, date: &Self::DateInner) -> bool {
261-
Self::provided_year_is_leap(date.0 .0.year)
260+
Self::provided_year_is_leap(date.0.year)
262261
}
263262

264263
/// The calendar-specific month code represented by `date`;
265264
/// since the Chinese calendar has leap months, an "L" is appended to the month code for
266265
/// leap months. For example, in a year where an intercalary month is added after the second
267266
/// month, the month codes for ordinal months 1, 2, 3, 4, 5 would be "M01", "M02", "M02L", "M03", "M04".
268267
fn month(&self, date: &Self::DateInner) -> types::MonthInfo {
269-
date.0.month()
268+
date.0.year.month(date.0.month)
270269
}
271270

272271
/// The calendar-specific day-of-month represented by `date`
273272
fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth {
274-
types::DayOfMonth(date.0 .0.day)
273+
date.0.day_of_month()
275274
}
276275

277276
/// Information of the day of the year
278277
fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear {
279-
types::DayOfYear(date.0.day_of_year())
278+
types::DayOfYear(date.0.year.day_of_year(date.0.month, date.0.day))
280279
}
281280

282281
fn any_calendar_kind(&self) -> Option<crate::AnyCalendarKind> {
283282
Some(crate::any_calendar::IntoAnyCalendar::kind(self))
284283
}
285284

286285
fn months_in_year(&self, date: &Self::DateInner) -> u8 {
287-
date.0.months_in_year_inner()
286+
date.0.months_in_year()
288287
}
289288
}
290289

@@ -307,7 +306,7 @@ impl<A: AsCalendar<Calendar = Chinese>> Date<A> {
307306
/// .expect("Failed to initialize Chinese Date instance.");
308307
///
309308
/// assert_eq!(date_chinese.cyclic_year().related_iso, 2023);
310-
/// assert_eq!(date_chinese.cyclic_year().year.get(), 40);
309+
/// assert_eq!(date_chinese.cyclic_year().year, 40);
311310
/// assert_eq!(date_chinese.month().ordinal, 6);
312311
/// assert_eq!(date_chinese.day_of_month().0, 11);
313312
/// ```
@@ -321,9 +320,9 @@ impl<A: AsCalendar<Calendar = Chinese>> Date<A> {
321320
.as_calendar()
322321
.get_precomputed_data()
323322
.load_or_compute_info(related_iso_year);
324-
let arithmetic = Inner::new_from_ordinals(year, month, day);
323+
year.validate_md(month, day)?;
325324
Ok(Date::from_raw(
326-
ChineseDateInner(ChineseBasedDateInner(arithmetic?)),
325+
ChineseDateInner(ArithmeticDate::new_unchecked(year, month, day)),
327326
calendar,
328327
))
329328
}
@@ -518,9 +517,9 @@ mod test {
518517
case.year, case.month, case.day, chinese,
519518
)
520519
.unwrap();
521-
let rd = Inner::rd_from_chinese_based_date_inner(date.inner.0).to_i64_date();
520+
let rd = date.to_rata_die().to_i64_date();
522521
let expected = case.expected;
523-
assert_eq!(rd, expected, "[{calendar_type}] RD from Chinese failed, with expected: {rd} and calculated: {expected}, for test case: {case:?}");
522+
assert_eq!(rd, expected, "[{calendar_type}] RD from Chinese failed, with expected: {expected} and calculated: {rd}, for test case: {case:?}");
524523
},
525524
);
526525
}
@@ -536,16 +535,14 @@ mod test {
536535
let chinese_cached = Chinese::new();
537536
while rd < max_rd && iters < max_iters {
538537
let rata_die = RataDie::new(rd);
539-
let iso = Iso.from_rata_die(rata_die);
540538

541539
do_twice(
542540
&chinese_calculating,
543541
&chinese_cached,
544542
|chinese, calendar_type| {
545-
let chinese = Inner::chinese_based_date_from_rd(&chinese, rata_die, iso.0);
546-
let result = Inner::rd_from_chinese_based_date_inner(chinese);
547-
let result_debug = result.to_i64_date();
548-
assert_eq!(result, rata_die, "[{calendar_type}] Failed roundtrip RD -> Chinese -> RD for RD: {rd}, with calculated: {result_debug} from Chinese date:\n{chinese:?}");
543+
let chinese = Date::from_rata_die(rata_die, chinese);
544+
let result = chinese.to_rata_die();
545+
assert_eq!(result, rata_die, "[{calendar_type}] Failed roundtrip RD -> Chinese -> RD for RD: {rata_die:?}, with calculated: {result:?} from Chinese date:\n{chinese:?}");
549546
},
550547
);
551548
rd += 7043;
@@ -567,7 +564,7 @@ mod test {
567564
assert_eq!(chinese.month().ordinal, 1);
568565
assert_eq!(chinese.month().standard_code.0, "M01");
569566
assert_eq!(chinese.day_of_month().0, 1);
570-
assert_eq!(chinese.cyclic_year().year.get(), 1);
567+
assert_eq!(chinese.cyclic_year().year, 1);
571568
assert_eq!(chinese.cyclic_year().related_iso, -2636);
572569
},
573570
)
@@ -660,7 +657,7 @@ mod test {
660657
chinese_date.is_in_leap_year(),
661658
"[{calendar_type}] {year} should be a leap year"
662659
);
663-
let new_year = chinese_date.inner.0.new_year();
660+
let new_year = chinese_date.inner.0.year.new_year();
664661
assert_eq!(
665662
expected_month,
666663
calendrical_calculations::chinese_based::get_leap_month_from_new_year::<
@@ -849,7 +846,7 @@ mod test {
849846
];
850847
for ordinal_code_pair in codes {
851848
let code = MonthCode(ordinal_code_pair.1);
852-
let ordinal = chinese_based_ordinal_lunar_month_from_code(code, year);
849+
let ordinal = year.parse_month_code(code);
853850
assert_eq!(
854851
ordinal,
855852
Some(ordinal_code_pair.0),
@@ -880,7 +877,7 @@ mod test {
880877
>::default()
881878
.load_or_compute_info(year);
882879
let code = MonthCode(code);
883-
let ordinal = chinese_based_ordinal_lunar_month_from_code(code, year);
880+
let ordinal = year.parse_month_code(code);
884881
assert_eq!(
885882
ordinal, None,
886883
"Invalid month code failed for year: {}, code: {code}",
@@ -1023,8 +1020,7 @@ mod test {
10231020
"[{calendar_type}] Related ISO failed for test case: {case:?}"
10241021
);
10251022
assert_eq!(
1026-
chinese_cyclic.get(),
1027-
case.expected_cyclic,
1023+
chinese_cyclic, case.expected_cyclic,
10281024
"[{calendar_type}] Cyclic year failed for test case: {case:?}"
10291025
);
10301026
assert_eq!(

0 commit comments

Comments
 (0)