Skip to content

Commit bccd8b4

Browse files
committed
split japanese calendar implementations
1 parent c460c96 commit bccd8b4

File tree

1 file changed

+109
-20
lines changed

1 file changed

+109
-20
lines changed

components/calendar/src/cal/japanese.rs

Lines changed: 109 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ pub struct Japanese {
7373
/// These eras are loaded from data, requiring a data provider capable of providing [`CalendarJapaneseExtendedV1`]
7474
/// data.
7575
#[derive(Clone, Debug, Default)]
76-
pub struct JapaneseExtended(Japanese);
76+
pub struct JapaneseExtended {
77+
eras: DataPayload<CalendarJapaneseExtendedV1>,
78+
}
7779

7880
impl Japanese {
7981
/// Creates a new [`Japanese`] using only modern eras (post-meiji) from compiled data.
@@ -116,11 +118,11 @@ impl JapaneseExtended {
116118
/// [📚 Help choosing a constructor](icu_provider::constructors)
117119
#[cfg(feature = "compiled_data")]
118120
pub const fn new() -> Self {
119-
Self(Japanese {
121+
Self {
120122
eras: DataPayload::from_static_ref(
121123
crate::provider::Baked::SINGLETON_CALENDAR_JAPANESE_EXTENDED_V1,
122124
),
123-
})
125+
}
124126
}
125127

126128
icu_provider::gen_buffer_data_constructors!(() -> error: DataError,
@@ -135,9 +137,9 @@ impl JapaneseExtended {
135137
pub fn try_new_unstable<D: DataProvider<CalendarJapaneseExtendedV1> + ?Sized>(
136138
provider: &D,
137139
) -> Result<Self, DataError> {
138-
Ok(Self(Japanese {
139-
eras: provider.load(Default::default())?.payload.cast(),
140-
}))
140+
Ok(Self {
141+
eras: provider.load(Default::default())?.payload,
142+
})
141143
}
142144
}
143145

@@ -168,6 +170,103 @@ const REIWA_START: EraStartDate = EraStartDate {
168170
};
169171

170172
impl GregorianYears for &'_ Japanese {
173+
fn extended_from_era_year(
174+
&self,
175+
era: Option<&[u8]>,
176+
year: i32,
177+
) -> Result<i32, UnknownEraError> {
178+
if let Ok(g) = CeBce.extended_from_era_year(era, year) {
179+
return Ok(g);
180+
}
181+
let Some(era) = era else {
182+
// unreachable, handled by CeBce
183+
return Err(UnknownEraError);
184+
};
185+
186+
// Avoid linear search by trying well known eras
187+
if era == b"reiwa" {
188+
return Ok(year - 1 + REIWA_START.year);
189+
} else if era == b"heisei" {
190+
return Ok(year - 1 + HEISEI_START.year);
191+
} else if era == b"showa" {
192+
return Ok(year - 1 + SHOWA_START.year);
193+
} else if era == b"taisho" {
194+
return Ok(year - 1 + TAISHO_START.year);
195+
} else if era == b"meiji" {
196+
return Ok(year - 1 + MEIJI_START.year);
197+
}
198+
199+
let era_start = self
200+
.eras
201+
.get()
202+
.dates_to_eras
203+
.iter()
204+
.rev()
205+
.find_map(|(s, e)| (e.as_bytes() == era).then_some(s))
206+
.ok_or(UnknownEraError)?;
207+
Ok(era_start.year + year - 1)
208+
}
209+
210+
fn era_year_from_extended(&self, year: i32, month: u8, day: u8) -> types::EraYear {
211+
let date: EraStartDate = EraStartDate { year, month, day };
212+
213+
let (start, era) = if date >= MEIJI_START
214+
&& self
215+
.eras
216+
.get()
217+
.dates_to_eras
218+
.last()
219+
.is_some_and(|(_, e)| e == tinystr!(16, "reiwa"))
220+
{
221+
// We optimize for the five "modern" post-Meiji eras, which are stored in a smaller
222+
// array and also hardcoded. The hardcoded version is not used if data indicates the
223+
// presence of newer eras.
224+
if date >= REIWA_START {
225+
(REIWA_START, tinystr!(16, "reiwa"))
226+
} else if date >= HEISEI_START {
227+
(HEISEI_START, tinystr!(16, "heisei"))
228+
} else if date >= SHOWA_START {
229+
(SHOWA_START, tinystr!(16, "showa"))
230+
} else if date >= TAISHO_START {
231+
(TAISHO_START, tinystr!(16, "taisho"))
232+
} else {
233+
(MEIJI_START, tinystr!(16, "meiji"))
234+
}
235+
} else {
236+
let data = &self.eras.get().dates_to_eras;
237+
match data.iter().rfind(|&(s, _)| date >= s) {
238+
None => {
239+
return types::EraYear {
240+
// TODO: return era indices?
241+
era_index: None,
242+
..CeBce.era_year_from_extended(year, month, day)
243+
};
244+
}
245+
Some((s, e)) => (s, e),
246+
}
247+
};
248+
249+
types::EraYear {
250+
era,
251+
era_index: None,
252+
year: year - start.year + 1,
253+
extended_year: year,
254+
ambiguity: types::YearAmbiguity::CenturyRequired,
255+
}
256+
}
257+
258+
fn debug_name(&self) -> &'static str {
259+
"Japanese"
260+
}
261+
262+
fn calendar_algorithm(&self) -> Option<crate::preferences::CalendarAlgorithm> {
263+
Some(crate::preferences::CalendarAlgorithm::Japanese)
264+
}
265+
}
266+
267+
impl_with_abstract_gregorian!(Japanese, JapaneseDateInner, Japanese, this, this);
268+
269+
impl GregorianYears for &'_ JapaneseExtended {
171270
fn extended_from_era_year(
172271
&self,
173272
era: Option<&[u8]>,
@@ -273,30 +372,20 @@ impl GregorianYears for &'_ Japanese {
273372
}
274373

275374
fn debug_name(&self) -> &'static str {
276-
if self.eras.get().dates_to_eras.len() > 10 {
277-
"Japanese (historical era data)"
278-
} else {
279-
"Japanese"
280-
}
375+
"Japanese (historical era data)"
281376
}
282377

283378
fn calendar_algorithm(&self) -> Option<crate::preferences::CalendarAlgorithm> {
284-
if self.eras.get().dates_to_eras.len() > 10 {
285-
None
286-
} else {
287-
Some(crate::preferences::CalendarAlgorithm::Japanese)
288-
}
379+
None
289380
}
290381
}
291382

292-
impl_with_abstract_gregorian!(Japanese, JapaneseDateInner, Japanese, this, this);
293-
294383
impl_with_abstract_gregorian!(
295384
JapaneseExtended,
296385
JapaneseExtendedDateInner,
297386
Japanese,
298387
this,
299-
&this.0
388+
this
300389
);
301390

302391
impl Date<Japanese> {
@@ -411,7 +500,7 @@ impl Date<JapaneseExtended> {
411500
year,
412501
month,
413502
day,
414-
&AbstractGregorian(&japanext_calendar.as_calendar().0),
503+
&AbstractGregorian(japanext_calendar.as_calendar()),
415504
)
416505
.map(ArithmeticDate::cast)
417506
.map(JapaneseExtendedDateInner)

0 commit comments

Comments
 (0)