@@ -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
7880impl 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
170172impl 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-
294383impl_with_abstract_gregorian ! (
295384 JapaneseExtended ,
296385 JapaneseExtendedDateInner ,
297386 Japanese ,
298387 this,
299- & this. 0
388+ this
300389) ;
301390
302391impl 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