@@ -11,7 +11,7 @@ use crate::error::{DateError, UnknownEraError};
1111use crate :: provider:: { CalendarJapaneseModernV1 , EraStartDate } ;
1212use crate :: { types, AsCalendar , Date } ;
1313use icu_provider:: prelude:: * ;
14- use tinystr:: tinystr;
14+ use tinystr:: { tinystr, TinyAsciiStr } ;
1515
1616/// The [Japanese Calendar] (with modern eras only)
1717///
@@ -36,9 +36,49 @@ use tinystr::tinystr;
3636///
3737/// These eras are loaded from data, requiring a data provider capable of providing [`CalendarJapaneseModernV1`]
3838/// data.
39- #[ derive( Clone , Debug , Default ) ]
39+ #[ derive( Clone , Debug , Copy ) ]
4040pub struct Japanese {
41- eras : DataPayload < CalendarJapaneseModernV1 > ,
41+ last_era : PackedEra ,
42+ }
43+
44+ impl Default for Japanese {
45+ fn default ( ) -> Self {
46+ Self {
47+ last_era : PackedEra :: new ( REIWA ) ,
48+ }
49+ }
50+ }
51+
52+ #[ derive( Clone , Debug , Copy ) ]
53+ struct PackedEra {
54+ // The year is stored as an offset from `REIWA`,
55+ // which works until 2274
56+ year : u8 ,
57+ month : u8 ,
58+ day : u8 ,
59+ name : TinyAsciiStr < 8 > ,
60+ }
61+
62+ impl PackedEra {
63+ const fn new ( v : ( EraStartDate , TinyAsciiStr < 16 > ) ) -> Self {
64+ Self {
65+ year : ( v. 0 . year - REIWA . 0 . year ) as u8 ,
66+ month : v. 0 . month ,
67+ day : v. 0 . day ,
68+ name : v. 1 . resize ( ) ,
69+ }
70+ }
71+
72+ const fn expand ( self ) -> ( EraStartDate , TinyAsciiStr < 16 > ) {
73+ (
74+ EraStartDate {
75+ year : self . year as i32 + REIWA . 0 . year ,
76+ month : self . month ,
77+ day : self . day ,
78+ } ,
79+ self . name . resize ( ) ,
80+ )
81+ }
4282}
4383
4484impl Japanese {
@@ -49,11 +89,27 @@ impl Japanese {
4989 /// [📚 Help choosing a constructor](icu_provider::constructors)
5090 #[ cfg( feature = "compiled_data" ) ]
5191 pub const fn new ( ) -> Self {
52- Self {
53- eras : DataPayload :: from_static_ref (
54- crate :: provider:: Baked :: SINGLETON_CALENDAR_JAPANESE_MODERN_V1 ,
55- ) ,
56- }
92+ let last_era = const {
93+ if let Some ( & zerovec:: ule:: tuple:: Tuple2ULE ( start, name) ) =
94+ crate :: provider:: Baked :: SINGLETON_CALENDAR_JAPANESE_MODERN_V1
95+ . dates_to_eras
96+ . as_slice ( )
97+ . as_ule_slice ( )
98+ . last ( )
99+ {
100+ PackedEra :: new ( (
101+ EraStartDate {
102+ year : i32:: from_le_bytes ( start. year . 0 ) ,
103+ month : start. month ,
104+ day : start. day ,
105+ } ,
106+ name,
107+ ) )
108+ } else {
109+ panic ! ( "Invalid era data" )
110+ }
111+ } ;
112+ Self { last_era }
57113 }
58114
59115 icu_provider:: gen_buffer_data_constructors!( ( ) -> error: DataError ,
@@ -69,36 +125,59 @@ impl Japanese {
69125 provider : & D ,
70126 ) -> Result < Self , DataError > {
71127 Ok ( Self {
72- eras : provider. load ( Default :: default ( ) ) ?. payload ,
128+ last_era : PackedEra :: new (
129+ provider
130+ . load ( Default :: default ( ) ) ?
131+ . payload
132+ . get ( )
133+ . dates_to_eras
134+ . last ( )
135+ . ok_or_else ( || DataError :: custom ( "Invalid era data" ) ) ?,
136+ ) ,
73137 } )
74138 }
75139}
76140
77- const MEIJI_START : EraStartDate = EraStartDate {
78- year : 1868 ,
79- month : 10 ,
80- day : 23 ,
81- } ;
82- const TAISHO_START : EraStartDate = EraStartDate {
83- year : 1912 ,
84- month : 7 ,
85- day : 30 ,
86- } ;
87- const SHOWA_START : EraStartDate = EraStartDate {
88- year : 1926 ,
89- month : 12 ,
90- day : 25 ,
91- } ;
92- const HEISEI_START : EraStartDate = EraStartDate {
93- year : 1989 ,
94- month : 1 ,
95- day : 8 ,
96- } ;
97- const REIWA_START : EraStartDate = EraStartDate {
98- year : 2019 ,
99- month : 5 ,
100- day : 1 ,
101- } ;
141+ const MEIJI : ( EraStartDate , TinyAsciiStr < 16 > ) = (
142+ EraStartDate {
143+ year : 1868 ,
144+ month : 10 ,
145+ day : 23 ,
146+ } ,
147+ tinystr ! ( 16 , "meiji" ) ,
148+ ) ;
149+ const TAISHO : ( EraStartDate , TinyAsciiStr < 16 > ) = (
150+ EraStartDate {
151+ year : 1912 ,
152+ month : 7 ,
153+ day : 30 ,
154+ } ,
155+ tinystr ! ( 16 , "taisho" ) ,
156+ ) ;
157+ const SHOWA : ( EraStartDate , TinyAsciiStr < 16 > ) = (
158+ EraStartDate {
159+ year : 1926 ,
160+ month : 12 ,
161+ day : 25 ,
162+ } ,
163+ tinystr ! ( 16 , "showa" ) ,
164+ ) ;
165+ const HEISEI : ( EraStartDate , TinyAsciiStr < 16 > ) = (
166+ EraStartDate {
167+ year : 1989 ,
168+ month : 1 ,
169+ day : 8 ,
170+ } ,
171+ tinystr ! ( 16 , "heisei" ) ,
172+ ) ;
173+ const REIWA : ( EraStartDate , TinyAsciiStr < 16 > ) = (
174+ EraStartDate {
175+ year : 2019 ,
176+ month : 5 ,
177+ day : 1 ,
178+ } ,
179+ tinystr ! ( 16 , "reiwa" ) ,
180+ ) ;
102181
103182impl GregorianYears for & ' _ Japanese {
104183 fn extended_from_era_year (
@@ -109,89 +188,36 @@ impl GregorianYears for &'_ Japanese {
109188 if let Ok ( g) = CeBce . extended_from_era_year ( era, year) {
110189 return Ok ( g) ;
111190 }
112- let Some ( era) = era else {
113- // unreachable, handled by CeBce
114- return Err ( UnknownEraError ) ;
115- } ;
116191
117- // Avoid linear search by trying well known eras
118- if era == b"reiwa" {
119- return Ok ( year - 1 + REIWA_START . year ) ;
120- } else if era == b"heisei" {
121- return Ok ( year - 1 + HEISEI_START . year ) ;
122- } else if era == b"showa" {
123- return Ok ( year - 1 + SHOWA_START . year ) ;
124- } else if era == b"taisho" {
125- return Ok ( year - 1 + TAISHO_START . year ) ;
126- } else if era == b"meiji" {
127- return Ok ( year - 1 + MEIJI_START . year ) ;
128- }
129-
130- let era_start = self
131- . eras
132- . get ( )
133- . dates_to_eras
134- . iter ( )
135- . rev ( )
136- . find_map ( |( s, e) | ( e. as_bytes ( ) == era) . then_some ( s) )
192+ let ( start, _) = [ self . last_era . expand ( ) , REIWA , HEISEI , SHOWA , TAISHO , MEIJI ]
193+ . into_iter ( )
194+ . find ( |( _, name) | era == Some ( name. as_bytes ( ) ) )
137195 . ok_or ( UnknownEraError ) ?;
138- Ok ( era_start. year + year - 1 )
196+
197+ Ok ( year - 1 + start. year )
139198 }
140199
141200 fn era_year_from_extended ( & self , year : i32 , month : u8 , day : u8 ) -> types:: EraYear {
142201 let date: EraStartDate = EraStartDate { year, month, day } ;
143202
144- if year < 1873 {
145- return types:: EraYear {
203+ if let Some ( ( start, era) ) = [ self . last_era . expand ( ) , REIWA , HEISEI , SHOWA , TAISHO , MEIJI ]
204+ . into_iter ( )
205+ . find ( |& ( start, _) | date >= start && year >= 1873 )
206+ {
207+ types:: EraYear {
208+ era,
146209 // TODO: return era indices?
147210 era_index : None ,
148- ..CeBce . era_year_from_extended ( year, month, day)
149- } ;
150- }
151-
152- let ( start, era) = if self
153- . eras
154- . get ( )
155- . dates_to_eras
156- . last ( )
157- . is_some_and ( |( _, e) | e == tinystr ! ( 16 , "reiwa" ) )
158- {
159- // We optimize for the five "modern" post-Meiji eras, which are stored in a smaller
160- // array and also hardcoded. The hardcoded version is not used if data indicates the
161- // presence of newer eras.
162- if date >= REIWA_START {
163- ( REIWA_START , tinystr ! ( 16 , "reiwa" ) )
164- } else if date >= HEISEI_START {
165- ( HEISEI_START , tinystr ! ( 16 , "heisei" ) )
166- } else if date >= SHOWA_START {
167- ( SHOWA_START , tinystr ! ( 16 , "showa" ) )
168- } else if date >= TAISHO_START {
169- ( TAISHO_START , tinystr ! ( 16 , "taisho" ) )
170- } else {
171- ( MEIJI_START , tinystr ! ( 16 , "meiji" ) )
211+ year : year - start. year + 1 ,
212+ extended_year : year,
213+ ambiguity : types:: YearAmbiguity :: CenturyRequired ,
172214 }
173215 } else {
174- let data = & self . eras . get ( ) . dates_to_eras ;
175- #[ allow( clippy:: unwrap_used) ] // binary search
176- match data. binary_search_by ( |( d, _) | d. cmp ( & date) ) {
177- Err ( 0 ) => {
178- return types:: EraYear {
179- // TODO: return era indices?
180- era_index : None ,
181- ..CeBce . era_year_from_extended ( year, month, day)
182- } ;
183- }
184- Ok ( index) => data. get ( index) . unwrap ( ) ,
185- Err ( index) => data. get ( index - 1 ) . unwrap ( ) ,
216+ types:: EraYear {
217+ // TODO: return era indices?
218+ era_index : None ,
219+ ..CeBce . era_year_from_extended ( year, month, day)
186220 }
187- } ;
188-
189- types:: EraYear {
190- era,
191- era_index : None ,
192- year : year - start. year + 1 ,
193- extended_year : year,
194- ambiguity : types:: YearAmbiguity :: CenturyRequired ,
195221 }
196222 }
197223
0 commit comments