@@ -13,7 +13,7 @@ use zerovec::{VarZeroVec, ZeroMap, ZeroVec};
1313use icu_pattern:: DoublePlaceholderPattern ;
1414
1515use crate :: dimension:: currency:: CurrencyCode ;
16- use crate :: dimension:: currency:: options:: Width ;
16+ use crate :: dimension:: currency:: options:: { CurrencyUsage , Width } ;
1717
1818#[ cfg( feature = "compiled_data" ) ]
1919/// Baked data
@@ -143,17 +143,26 @@ pub struct CurrencyPatternConfig {
143143 pub narrow_placeholder_value : Option < PlaceholderValue > ,
144144}
145145
146+ // Fallback pattern: "{0} {1}" (number followed by currency with space, e.g. "10 $")
147+ //
148+ // Even though the baked data handles the fallback at data generation time,
149+ // we have the fallback here for users feeding their own data without
150+ // handling the fallback logic in their data generation.
151+ const FALLBACK_PATTERN : & DoublePlaceholderPattern =
152+ DoublePlaceholderPattern :: from_ref_store_unchecked ( "\x02 \x05 " ) ;
153+
146154impl < ' a > CurrencyEssentials < ' a > {
147155 /// Returns the formatted currency name/symbol,
148156 /// the currency pattern for the given width and currency,
149157 /// and the pattern selection.
150158 pub ( crate ) fn name_and_pattern (
151159 & ' a self ,
152160 width : Width ,
161+ usage : CurrencyUsage ,
153162 currency : & ' a CurrencyCode ,
154163 ) -> (
155164 & ' a str ,
156- Option < & ' a DoublePlaceholderPattern > ,
165+ & ' a DoublePlaceholderPattern ,
157166 Option < & ' a DoublePlaceholderPattern > ,
158167 PatternSelection ,
159168 ) {
@@ -178,16 +187,28 @@ impl<'a> CurrencyEssentials<'a> {
178187 Width :: Narrow => config. narrow_pattern_selection ,
179188 } ;
180189
181- let pos_pattern = match pattern_selection {
182- PatternSelection :: Standard => self . standard_pattern ( ) ,
183- PatternSelection :: StandardAlphaNextToNumber => {
190+ let pos_pattern = match ( usage, pattern_selection) {
191+ ( CurrencyUsage :: Accounting , PatternSelection :: Standard ) => {
192+ self . accounting_positive_pattern ( )
193+ }
194+ ( CurrencyUsage :: Accounting , PatternSelection :: StandardAlphaNextToNumber ) => {
195+ self . accounting_alpha_next_to_number_positive_pattern ( )
196+ }
197+ ( _, PatternSelection :: Standard ) => self . standard_pattern ( ) ,
198+ ( _, PatternSelection :: StandardAlphaNextToNumber ) => {
184199 self . standard_alpha_next_to_number_pattern ( )
185200 }
186201 } ;
187202
188- let neg_pattern = match pattern_selection {
189- PatternSelection :: Standard => self . standard_negative_pattern ( ) ,
190- PatternSelection :: StandardAlphaNextToNumber => {
203+ let neg_pattern = match ( usage, pattern_selection) {
204+ ( CurrencyUsage :: Accounting , PatternSelection :: Standard ) => {
205+ self . accounting_negative_pattern ( )
206+ }
207+ ( CurrencyUsage :: Accounting , PatternSelection :: StandardAlphaNextToNumber ) => {
208+ self . accounting_alpha_next_to_number_negative_pattern ( )
209+ }
210+ ( _, PatternSelection :: Standard ) => self . standard_negative_pattern ( ) ,
211+ ( _, PatternSelection :: StandardAlphaNextToNumber ) => {
191212 self . standard_alpha_next_to_number_negative_pattern ( )
192213 }
193214 } ;
@@ -196,10 +217,23 @@ impl<'a> CurrencyEssentials<'a> {
196217 }
197218
198219 /// Returns the standard pattern.
199- pub fn standard_pattern ( & self ) -> Option < & DoublePlaceholderPattern > {
220+ ///
221+ /// If the standard pattern is missing (which should only happen in corrupt
222+ /// or incomplete custom data), this returns a default safety pattern `"{1}{0}"`.
223+ /// Note that this is a safety default, not a CLDR-defined fallback.
224+ pub fn standard_pattern ( & self ) -> & DoublePlaceholderPattern {
200225 self . patterns
201226 . get ( self . indices . standard as usize )
202- . or_else ( || self . patterns . get ( 0 ) )
227+ . unwrap_or_else ( || {
228+ debug_assert ! (
229+ false ,
230+ "Standard pattern index {} is out of bounds for patterns of length {}" ,
231+ self . indices. standard,
232+ self . patterns. len( )
233+ ) ;
234+ // GIGO
235+ FALLBACK_PATTERN
236+ } )
203237 }
204238
205239 /// Returns the standard negative pattern if specified.
@@ -209,14 +243,24 @@ impl<'a> CurrencyEssentials<'a> {
209243 . and_then ( |idx| self . patterns . get ( idx as usize ) )
210244 }
211245
212- /// Returns the `standard_alpha_next_to_number` pattern, falling back to `standard_pattern` if not present.
213- pub fn standard_alpha_next_to_number_pattern ( & self ) -> Option < & DoublePlaceholderPattern > {
246+ /// Returns the `standard_alpha_next_to_number` pattern.
247+ ///
248+ /// Fallback hierarchy:
249+ /// `standard_alpha_next_to_number` -> `standard`
250+ ///
251+ /// Even though the baked data handles the fallback at data generation time,
252+ /// we have the fallback here for users feeding their own data without
253+ /// handling the fallback logic in their data generation.
254+ pub fn standard_alpha_next_to_number_pattern ( & self ) -> & DoublePlaceholderPattern {
214255 self . patterns
215256 . get ( self . indices . standard_alpha_next_to_number as usize )
216- . or_else ( || self . standard_pattern ( ) )
257+ . unwrap_or_else ( || self . standard_pattern ( ) )
217258 }
218259
219260 /// Returns the `standard_alpha_next_to_number` negative pattern if specified, falling back to standard negative.
261+ ///
262+ /// Fallback hierarchy:
263+ /// `standard_alpha_next_to_number_negative` -> `standard_negative`
220264 pub fn standard_alpha_next_to_number_negative_pattern (
221265 & self ,
222266 ) -> Option < & DoublePlaceholderPattern > {
@@ -226,30 +270,49 @@ impl<'a> CurrencyEssentials<'a> {
226270 . or_else ( || self . standard_negative_pattern ( ) )
227271 }
228272
229- /// Returns the positive accounting pattern, falling back to `standard_pattern` if not present.
230- pub fn accounting_positive_pattern ( & self ) -> Option < & DoublePlaceholderPattern > {
273+ /// Returns the positive accounting pattern.
274+ ///
275+ /// Fallback hierarchy:
276+ /// `accounting_positive` -> `standard`
277+ ///
278+ /// Even though the baked data handles the fallback at data generation time,
279+ /// we have the fallback here for users feeding their own data without
280+ /// handling the fallback logic in their data generation.
281+ pub fn accounting_positive_pattern ( & self ) -> & DoublePlaceholderPattern {
231282 self . patterns
232283 . get ( self . indices . accounting_positive as usize )
233- . or_else ( || self . standard_pattern ( ) )
284+ . unwrap_or_else ( || self . standard_pattern ( ) )
234285 }
235286
236- /// Returns the negative accounting pattern if present.
287+ /// Returns the negative accounting pattern if present, falling back to standard negative.
288+ ///
289+ /// Fallback hierarchy:
290+ /// `accounting_negative` -> `standard_negative`
237291 pub fn accounting_negative_pattern ( & self ) -> Option < & DoublePlaceholderPattern > {
238292 self . indices
239293 . accounting_negative
240294 . and_then ( |idx| self . patterns . get ( idx as usize ) )
295+ . or_else ( || self . standard_negative_pattern ( ) )
241296 }
242297
243- /// Returns the positive `accounting_alpha_next_to_number` pattern, falling back to accounting or standard.
244- pub fn accounting_alpha_next_to_number_positive_pattern (
245- & self ,
246- ) -> Option < & DoublePlaceholderPattern > {
298+ /// Returns the positive `accounting_alpha_next_to_number` pattern.
299+ ///
300+ /// Fallback hierarchy:
301+ /// `accounting_alpha_next_to_number_positive` -> `standard_alpha_next_to_number` -> `standard`
302+ ///
303+ /// Even though the baked data handles the fallback at data generation time,
304+ /// we have the fallback here for users feeding their own data without
305+ /// handling the fallback logic in their data generation.
306+ pub fn accounting_alpha_next_to_number_positive_pattern ( & self ) -> & DoublePlaceholderPattern {
247307 self . patterns
248308 . get ( self . indices . accounting_alpha_next_to_number_positive as usize )
249- . or_else ( || self . accounting_positive_pattern ( ) )
309+ . unwrap_or_else ( || self . standard_alpha_next_to_number_pattern ( ) )
250310 }
251311
252312 /// Returns the negative `accounting_alpha_next_to_number` pattern, falling back to `accounting_negative_pattern`.
313+ ///
314+ /// Fallback hierarchy:
315+ /// `accounting_alpha_next_to_number_negative` -> `accounting_negative` -> `standard_negative`
253316 pub fn accounting_alpha_next_to_number_negative_pattern (
254317 & self ,
255318 ) -> Option < & DoublePlaceholderPattern > {
@@ -259,3 +322,14 @@ impl<'a> CurrencyEssentials<'a> {
259322 . or_else ( || self . accounting_negative_pattern ( ) )
260323 }
261324}
325+
326+ #[ cfg( test) ]
327+ mod tests {
328+ use super :: * ;
329+ use writeable:: assert_writeable_eq;
330+
331+ #[ test]
332+ fn test_fallback_pattern ( ) {
333+ assert_writeable_eq ! ( FALLBACK_PATTERN . interpolate( ( "10" , "$" ) ) , "10 $" ) ;
334+ }
335+ }
0 commit comments