@@ -10,7 +10,7 @@ use icu::datetime::fieldsets::enums::*;
10
10
use icu:: datetime:: options:: Length ;
11
11
use icu:: datetime:: provider:: calendar:: { DateSkeletonPatterns , TimeLengths } ;
12
12
use icu:: datetime:: provider:: fields:: components;
13
- use icu:: datetime:: provider:: pattern:: { reference, runtime} ;
13
+ use icu:: datetime:: provider:: pattern:: { reference, runtime, CoarseHourCycle } ;
14
14
use icu:: datetime:: provider:: skeleton:: PatternPlurals ;
15
15
use icu:: datetime:: provider:: * ;
16
16
use icu:: plurals:: PluralElements ;
@@ -19,6 +19,71 @@ use icu_provider::prelude::*;
19
19
20
20
use super :: DatagenCalendar ;
21
21
22
+ enum ExactOrSynthetic < T > {
23
+ Exact ( T ) ,
24
+ Synthetic ( T ) ,
25
+ }
26
+
27
+ impl < T > ExactOrSynthetic < T > {
28
+ pub fn map < V > ( self , mut f : impl FnMut ( T ) -> V ) -> ExactOrSynthetic < V > {
29
+ use ExactOrSynthetic :: * ;
30
+ match self {
31
+ Exact ( t) => Exact ( f ( t) ) ,
32
+ Synthetic ( t) => Synthetic ( f ( t) ) ,
33
+ }
34
+ }
35
+ pub fn inner ( & self ) -> & T {
36
+ use ExactOrSynthetic :: * ;
37
+ match self {
38
+ Exact ( t) => t,
39
+ Synthetic ( t) => t,
40
+ }
41
+ }
42
+ pub fn into_inner ( self ) -> T {
43
+ use ExactOrSynthetic :: * ;
44
+ match self {
45
+ Exact ( t) => t,
46
+ Synthetic ( t) => t,
47
+ }
48
+ }
49
+ }
50
+
51
+ fn select_pattern < ' data > (
52
+ bag : components:: Bag ,
53
+ skeletons : & DateSkeletonPatterns < ' data > ,
54
+ preferred_hour_cycle : CoarseHourCycle ,
55
+ length_patterns : & GenericLengthPatterns < ' data > ,
56
+ ) -> ExactOrSynthetic < PatternPlurals < ' data > > {
57
+ use icu:: datetime:: provider:: pattern:: { runtime, PatternItem } ;
58
+ use icu:: datetime:: provider:: skeleton:: { create_best_pattern_for_fields, BestSkeleton } ;
59
+ use icu_locale_core:: preferences:: extensions:: unicode:: keywords:: HourCycle ;
60
+
61
+ let default_hour_cycle = match preferred_hour_cycle {
62
+ CoarseHourCycle :: H11H12 => HourCycle :: H12 ,
63
+ CoarseHourCycle :: H23 => HourCycle :: H23 ,
64
+ } ;
65
+ let fields = bag. to_vec_fields ( default_hour_cycle) ;
66
+ match create_best_pattern_for_fields ( skeletons, length_patterns, & fields, & bag, false ) {
67
+ BestSkeleton :: AllFieldsMatch ( p) => ExactOrSynthetic :: Exact ( p) ,
68
+ BestSkeleton :: MissingOrExtraFields ( p) => ExactOrSynthetic :: Synthetic ( p) ,
69
+ BestSkeleton :: NoMatch => {
70
+ // Build a last-resort pattern that contains all of the requested fields.
71
+ // This is NOT in the CLDR standard! Better would be:
72
+ // - Use Append Items?
73
+ // - Fall back to the format from the Gregorian or Generic calendar?
74
+ // - Bubble up an error of some sort?
75
+ // See issue: <https://github.com/unicode-org/icu4x/issues/586>
76
+ let pattern_items = fields
77
+ . into_iter ( )
78
+ . flat_map ( |field| [ PatternItem :: Literal ( ' ' ) , PatternItem :: Field ( field) ] )
79
+ . skip ( 1 )
80
+ . collect :: < Vec < _ > > ( ) ;
81
+ let pattern = runtime:: Pattern :: from ( pattern_items) ;
82
+ ExactOrSynthetic :: Synthetic ( PatternPlurals :: SinglePattern ( pattern) )
83
+ }
84
+ }
85
+ }
86
+
22
87
impl SourceDataProvider {
23
88
fn load_neo_skeletons_key < M > (
24
89
& self ,
@@ -68,24 +133,25 @@ impl SourceDataProvider {
68
133
DateSkeletonPatterns :: from ( & data. datetime_formats . available_formats ) ;
69
134
70
135
fn expand_pp_to_pe (
71
- pp : PatternPlurals ,
72
- ) -> PluralElements < icu :: datetime :: provider :: pattern :: runtime:: Pattern > {
73
- match pp {
136
+ value : ExactOrSynthetic < PatternPlurals > ,
137
+ ) -> ExactOrSynthetic < PluralElements < runtime:: Pattern > > {
138
+ value . map ( |pp| match pp {
74
139
PatternPlurals :: MultipleVariants ( variants) => PluralElements :: new ( variants. other )
75
140
. with_zero_value ( variants. zero . clone ( ) )
76
141
. with_one_value ( variants. one . clone ( ) )
77
142
. with_two_value ( variants. two . clone ( ) )
78
143
. with_few_value ( variants. few . clone ( ) )
79
144
. with_many_value ( variants. many . clone ( ) ) ,
80
145
PatternPlurals :: SinglePattern ( pattern) => PluralElements :: new ( pattern) ,
81
- }
146
+ } )
82
147
}
83
148
84
149
let [ long, medium, short] = [ Length :: Long , Length :: Medium , Length :: Short ]
85
150
. map ( |length| to_components_bag ( length, attributes, & data) )
86
151
. map ( |components| {
87
152
// TODO: Use a Skeleton here in order to retain 'E' vs 'c'
88
- let pattern = expand_pp_to_pe ( components. select_pattern (
153
+ let pattern = expand_pp_to_pe ( select_pattern (
154
+ components,
89
155
& skeleton_patterns,
90
156
time_lengths_v1. preferred_hour_cycle ,
91
157
& length_combinations_v1,
@@ -105,12 +171,14 @@ impl SourceDataProvider {
105
171
components_with_era. era = Some ( components:: Text :: Short ) ;
106
172
(
107
173
pattern,
108
- Some ( expand_pp_to_pe ( components_with_full_year. select_pattern (
174
+ Some ( expand_pp_to_pe ( select_pattern (
175
+ components_with_full_year,
109
176
& skeleton_patterns,
110
177
time_lengths_v1. preferred_hour_cycle ,
111
178
& length_combinations_v1,
112
179
) ) ) ,
113
- Some ( expand_pp_to_pe ( components_with_era. select_pattern (
180
+ Some ( expand_pp_to_pe ( select_pattern (
181
+ components_with_era,
114
182
& skeleton_patterns,
115
183
time_lengths_v1. preferred_hour_cycle ,
116
184
& length_combinations_v1,
@@ -125,12 +193,14 @@ impl SourceDataProvider {
125
193
components_with_second. second = Some ( components:: Numeric :: Numeric ) ;
126
194
(
127
195
pattern,
128
- Some ( expand_pp_to_pe ( components_with_minute. select_pattern (
196
+ Some ( expand_pp_to_pe ( select_pattern (
197
+ components_with_minute,
129
198
& skeleton_patterns,
130
199
time_lengths_v1. preferred_hour_cycle ,
131
200
& length_combinations_v1,
132
201
) ) ) ,
133
- Some ( expand_pp_to_pe ( components_with_second. select_pattern (
202
+ Some ( expand_pp_to_pe ( select_pattern (
203
+ components_with_second,
134
204
& skeleton_patterns,
135
205
time_lengths_v1. preferred_hour_cycle ,
136
206
& length_combinations_v1,
@@ -142,31 +212,37 @@ impl SourceDataProvider {
142
212
} ) ;
143
213
let builder = PackedPatternsBuilder {
144
214
standard : LengthPluralElements {
145
- long : long. 0 . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ,
146
- medium : medium. 0 . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ,
147
- short : short. 0 . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ,
215
+ long : long. 0 . inner ( ) . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ,
216
+ medium : medium. 0 . inner ( ) . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ,
217
+ short : short. 0 . inner ( ) . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ,
148
218
} ,
149
219
variant0 : Some ( LengthPluralElements {
150
220
long : long
151
221
. 1
152
- . unwrap_or ( long. 0 . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ) ,
222
+ . map ( |x| x. into_inner ( ) )
223
+ . unwrap_or ( long. 0 . inner ( ) . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ) ,
153
224
medium : medium
154
225
. 1
155
- . unwrap_or ( medium. 0 . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ) ,
226
+ . map ( |x| x. into_inner ( ) )
227
+ . unwrap_or ( medium. 0 . inner ( ) . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ) ,
156
228
short : short
157
229
. 1
158
- . unwrap_or ( short. 0 . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ) ,
230
+ . map ( |x| x. into_inner ( ) )
231
+ . unwrap_or ( short. 0 . inner ( ) . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ) ,
159
232
} ) ,
160
233
variant1 : Some ( LengthPluralElements {
161
234
long : long
162
235
. 2
163
- . unwrap_or ( long. 0 . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ) ,
236
+ . map ( |x| x. into_inner ( ) )
237
+ . unwrap_or ( long. 0 . inner ( ) . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ) ,
164
238
medium : medium
165
239
. 2
166
- . unwrap_or ( medium. 0 . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ) ,
240
+ . map ( |x| x. into_inner ( ) )
241
+ . unwrap_or ( medium. 0 . inner ( ) . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ) ,
167
242
short : short
168
243
. 2
169
- . unwrap_or ( short. 0 . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ) ,
244
+ . map ( |x| x. into_inner ( ) )
245
+ . unwrap_or ( short. 0 . inner ( ) . as_ref ( ) . map ( runtime:: Pattern :: as_ref) ) ,
170
246
} ) ,
171
247
} ;
172
248
Ok ( builder. build ( ) )
@@ -650,11 +726,14 @@ mod date_skeleton_consistency_tests {
650
726
// TODO: Use a Skeleton here in order to retain 'E' vs 'c'
651
727
let parsed_skeleton: reference:: Pattern = info. skeleton . parse ( ) . unwrap ( ) ;
652
728
let components = components:: Bag :: from ( & parsed_skeleton) ;
653
- let selected_pattern = match components. select_pattern (
729
+ let selected_pattern = match select_pattern (
730
+ components,
654
731
data. skeleton_patterns ,
655
732
data. preferred_hour_cycle ,
656
733
data. length_combinations_v1 ,
657
- ) {
734
+ )
735
+ . into_inner ( )
736
+ {
658
737
PatternPlurals :: SinglePattern ( x) => x,
659
738
PatternPlurals :: MultipleVariants ( _) => unreachable ! ( ) ,
660
739
} ;
0 commit comments