77#[ cfg( feature = "datagen" ) ]
88use crate :: provider:: packed_pattern:: GenericUnpackedPatterns ;
99use crate :: provider:: packed_pattern:: { GenericPackedPatterns , PackedPatternsBuilderHelper } ;
10+ use crate :: provider:: pattern:: runtime:: PatternBorrowed ;
1011use crate :: provider:: pattern:: runtime:: { Pattern , PatternULE } ;
1112use icu_provider:: prelude:: * ;
1213use zerovec:: VarZeroVec ;
@@ -128,6 +129,40 @@ pub enum RangePatternInfo<'a> {
128129 FullRange ( Pattern < ' a > ) ,
129130}
130131
132+ impl < ' a > RangePatternInfo < ' a > {
133+ /// Gets the inner pattern.
134+ pub fn pattern ( & self ) -> & Pattern < ' a > {
135+ match self {
136+ Self :: Symmetric ( p) => p,
137+ Self :: FullRange ( p) => p,
138+ }
139+ }
140+ }
141+
142+ /// Fully borrowed version of [`RangePatternInfo`].
143+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
144+ pub enum RangePatternInfoBorrowed < ' a > {
145+ /// Symmetric pattern: `[sub] [glue] [sub]`, where the sub-pattern is shared.
146+ Symmetric ( PatternBorrowed < ' a > ) ,
147+ /// Full Range pattern: the entire range pattern is stored.
148+ FullRange ( PatternBorrowed < ' a > ) ,
149+ }
150+
151+ impl < ' a > From < RangePatternInfoBorrowed < ' a > > for RangePatternInfo < ' a > {
152+ fn from ( other : RangePatternInfoBorrowed < ' a > ) -> Self {
153+ match other {
154+ RangePatternInfoBorrowed :: Symmetric ( p) => RangePatternInfo :: Symmetric ( p. as_pattern ( ) ) ,
155+ RangePatternInfoBorrowed :: FullRange ( p) => RangePatternInfo :: FullRange ( p. as_pattern ( ) ) ,
156+ }
157+ }
158+ }
159+
160+ impl < ' a > zerofrom:: ZeroFrom < ' a , RangePatternInfoBorrowed < ' a > > for RangePatternInfo < ' a > {
161+ fn zero_from ( other : & ' a RangePatternInfoBorrowed < ' a > ) -> Self {
162+ Self :: from ( * other)
163+ }
164+ }
165+
131166/// A bitset encoding which fields are present in the `GreatestDifference` pattern list
132167/// and their range structure.
133168///
@@ -235,55 +270,53 @@ fn resolve_fallback(header: GreatestDifferenceHeader, requested: u8, max_value:
235270 None
236271}
237272
238- impl < ' data > PatternsByGreatestDifference < ' data > {
239- /// Internal helper to retrieve and construct `RangePatternInfo` for a resolved field index.
240- ///
241- /// GIGO: If the `resolved_field_idx` is `Absent`, it returns a default symmetric pattern
242- /// to avoid panicking at runtime.
243- fn get_pattern_internal < ' a > ( & ' a self , resolved_field_idx : u8 ) -> RangePatternInfo < ' a > {
244- let state = self . header . get_state ( resolved_field_idx) ;
245- let start_idx = self . header . get_pattern_index ( resolved_field_idx) ;
273+ impl PatternsByGreatestDifferenceULE {
274+ fn get_pattern_internal < ' a > ( & ' a self , resolved_field_idx : u8 ) -> RangePatternInfoBorrowed < ' a > {
275+ use zerovec:: ule:: AsULE ;
276+ let header = <GreatestDifferenceHeader as AsULE >:: from_unaligned ( self . header ) ;
277+ let state = header. get_state ( resolved_field_idx) ;
278+ let start_idx = header. get_pattern_index ( resolved_field_idx) ;
246279
247280 let get_pat = |offset| {
248281 self . patterns
249282 . get ( start_idx + offset)
250- . map ( <Pattern as zerofrom:: ZeroFrom < PatternULE > >:: zero_from)
251- . unwrap_or_default ( )
283+ . map ( <PatternBorrowed as zerofrom:: ZeroFrom < PatternULE > >:: zero_from)
284+ . unwrap_or ( PatternBorrowed :: DEFAULT )
252285 } ;
253286
254287 match state {
255- RangeStructure :: Absent => RangePatternInfo :: Symmetric ( Pattern :: default ( ) ) ,
256- RangeStructure :: Symmetric => RangePatternInfo :: Symmetric ( get_pat ( 0 ) ) ,
257- RangeStructure :: FullRange => RangePatternInfo :: FullRange ( get_pat ( 0 ) ) ,
288+ RangeStructure :: Absent => RangePatternInfoBorrowed :: Symmetric ( PatternBorrowed :: DEFAULT ) ,
289+ RangeStructure :: Symmetric => RangePatternInfoBorrowed :: Symmetric ( get_pat ( 0 ) ) ,
290+ RangeStructure :: FullRange => RangePatternInfoBorrowed :: FullRange ( get_pat ( 0 ) ) ,
258291 }
259292 }
260293
261294 /// Gets the pattern info for the given date field, falling back to larger fields if necessary.
262295 pub fn get_date_pattern < ' a > (
263296 & ' a self ,
264297 field : DateGreatestDifferenceField ,
265- ) -> Option < RangePatternInfo < ' a > > {
266- let resolved_field_idx = resolve_fallback (
267- self . header ,
268- field as u8 ,
269- DateGreatestDifferenceField :: MAX_VALUE ,
270- ) ?;
298+ ) -> Option < RangePatternInfoBorrowed < ' a > > {
299+ use zerovec:: ule:: AsULE ;
300+ let header = <GreatestDifferenceHeader as AsULE >:: from_unaligned ( self . header ) ;
301+ let resolved_field_idx =
302+ resolve_fallback ( header, field as u8 , DateGreatestDifferenceField :: MAX_VALUE ) ?;
271303 Some ( self . get_pattern_internal ( resolved_field_idx) )
272304 }
273305
274306 /// Gets the pattern info for the given time field, falling back to larger fields if necessary.
275307 pub fn get_time_pattern < ' a > (
276308 & ' a self ,
277309 field : TimeGreatestDifferenceField ,
278- ) -> Option < RangePatternInfo < ' a > > {
279- let resolved_field_idx = resolve_fallback (
280- self . header ,
281- field as u8 ,
282- TimeGreatestDifferenceField :: MAX_VALUE ,
283- ) ?;
310+ ) -> Option < RangePatternInfoBorrowed < ' a > > {
311+ use zerovec:: ule:: AsULE ;
312+ let header = <GreatestDifferenceHeader as AsULE >:: from_unaligned ( self . header ) ;
313+ let resolved_field_idx =
314+ resolve_fallback ( header, field as u8 , TimeGreatestDifferenceField :: MAX_VALUE ) ?;
284315 Some ( self . get_pattern_internal ( resolved_field_idx) )
285316 }
317+ }
286318
319+ impl < ' data > PatternsByGreatestDifference < ' data > {
287320 /// Construct from an iterator of (`bit_index`, `pattern_info`).
288321 ///
289322 /// The `bit_index` must be <= 3.
@@ -540,23 +573,39 @@ mod tests {
540573 . is_date_field_present( DateGreatestDifferenceField :: Year )
541574 ) ;
542575
576+ let pgd_ule_box = zerovec:: ule:: encode_varule_to_box ( & pgd) ;
577+ let pgd: & PatternsByGreatestDifferenceULE = & pgd_ule_box;
578+
579+ let info_a = RangePatternInfo :: Symmetric ( pattern1) ;
580+ let info_b = RangePatternInfo :: Symmetric ( pattern2) ;
581+
543582 // Day difference should return Day pattern.
544583 assert_eq ! (
545- pgd. get_date_pattern( DateGreatestDifferenceField :: Day ) ,
546- Some ( RangePatternInfo :: Symmetric ( pattern1. clone( ) ) )
584+ pgd. get_date_pattern( DateGreatestDifferenceField :: Day )
585+ . map( RangePatternInfo :: from)
586+ . as_ref( ) ,
587+ Some ( & info_a)
547588 ) ;
548589 // Month difference should fall back to Year pattern (since Month is absent but Year is present).
549590 assert_eq ! (
550- pgd. get_date_pattern( DateGreatestDifferenceField :: Month ) ,
551- Some ( RangePatternInfo :: Symmetric ( pattern2. clone( ) ) )
591+ pgd. get_date_pattern( DateGreatestDifferenceField :: Month )
592+ . map( RangePatternInfo :: from)
593+ . as_ref( ) ,
594+ Some ( & info_b)
552595 ) ;
553596 // Year difference should return Year pattern.
554597 assert_eq ! (
555- pgd. get_date_pattern( DateGreatestDifferenceField :: Year ) ,
556- Some ( RangePatternInfo :: Symmetric ( pattern2. clone( ) ) )
598+ pgd. get_date_pattern( DateGreatestDifferenceField :: Year )
599+ . map( RangePatternInfo :: from)
600+ . as_ref( ) ,
601+ Some ( & info_b)
557602 ) ;
558603 // Era difference should return None (since Era is absent and no larger field is present).
559- assert_eq ! ( pgd. get_date_pattern( DateGreatestDifferenceField :: Era ) , None ) ;
604+ assert_eq ! (
605+ pgd. get_date_pattern( DateGreatestDifferenceField :: Era )
606+ . as_ref( ) ,
607+ None
608+ ) ;
560609 }
561610
562611 #[ test]
@@ -571,8 +620,8 @@ mod tests {
571620 . unwrap ( )
572621 . to_runtime_pattern ( ) ;
573622
574- let info_d = RangePatternInfo :: Symmetric ( pattern_d. clone ( ) ) ;
575- let info_y = RangePatternInfo :: Symmetric ( pattern_y. clone ( ) ) ;
623+ let info_d = RangePatternInfo :: Symmetric ( pattern_d) ;
624+ let info_y = RangePatternInfo :: Symmetric ( pattern_y) ;
576625
577626 // Valid date patterns
578627 let pgd = PatternsByGreatestDifference :: try_from_date_patterns (
@@ -589,20 +638,22 @@ mod tests {
589638 assert_eq ! (
590639 pgd. patterns
591640 . get( 0 )
592- . map( <Pattern as zerofrom:: ZeroFrom <PatternULE >>:: zero_from) ,
593- Some ( pattern_d. clone( ) )
641+ . map( <Pattern as zerofrom:: ZeroFrom <PatternULE >>:: zero_from)
642+ . as_ref( ) ,
643+ Some ( info_d. pattern( ) )
594644 ) ;
595645 assert_eq ! (
596646 pgd. patterns
597647 . get( 1 )
598- . map( <Pattern as zerofrom:: ZeroFrom <PatternULE >>:: zero_from) ,
599- Some ( pattern_y. clone( ) )
648+ . map( <Pattern as zerofrom:: ZeroFrom <PatternULE >>:: zero_from)
649+ . as_ref( ) ,
650+ Some ( info_y. pattern( ) )
600651 ) ;
601652
602653 // Unsorted input in BTreeMap::from is automatically sorted
603654 let pgd2 = PatternsByGreatestDifference :: try_from_date_patterns (
604655 alloc:: collections:: BTreeMap :: from ( [
605- ( DateGreatestDifferenceField :: Year , info_y. clone ( ) ) ,
656+ ( DateGreatestDifferenceField :: Year , info_y) ,
606657 ( DateGreatestDifferenceField :: Day , info_d. clone ( ) ) ,
607658 ] ) ,
608659 )
@@ -611,8 +662,9 @@ mod tests {
611662 assert_eq ! (
612663 pgd2. patterns
613664 . get( 0 )
614- . map( <Pattern as zerofrom:: ZeroFrom <PatternULE >>:: zero_from) ,
615- Some ( pattern_d. clone( ) )
665+ . map( <Pattern as zerofrom:: ZeroFrom <PatternULE >>:: zero_from)
666+ . as_ref( ) ,
667+ Some ( info_d. pattern( ) )
616668 ) ;
617669
618670 // Empty
@@ -708,8 +760,8 @@ mod try_from_patterns_tests {
708760 let pat_b = Pattern :: from_str ( "m" ) . unwrap ( ) ;
709761
710762 let info_a = RangePatternInfo :: Symmetric ( pat_a. clone ( ) ) ;
711- let info_b = RangePatternInfo :: Symmetric ( pat_b. clone ( ) ) ;
712- let info_c = RangePatternInfo :: FullRange ( pat_a. clone ( ) ) ;
763+ let info_b = RangePatternInfo :: Symmetric ( pat_b) ;
764+ let info_c = RangePatternInfo :: FullRange ( pat_a) ;
713765
714766 // 1. All different -> no dedup
715767 let input = vec ! [
@@ -726,20 +778,26 @@ mod try_from_patterns_tests {
726778 // Header value: 0b00100101 = 0x25
727779 assert_eq ! ( pgd. header. 0 , 0x25 ) ;
728780 assert_eq ! ( pgd. patterns. len( ) , 3 ) ; // 1 (Symmetric) + 1 (Symmetric) + 1 (FullRange) = 3
781+
782+ let pgd_ule_box = zerovec:: ule:: encode_varule_to_box ( & pgd) ;
783+ let pgd: & PatternsByGreatestDifferenceULE = & pgd_ule_box;
729784 assert_eq ! (
730785 pgd. get_date_pattern( DateGreatestDifferenceField :: Day )
731- . unwrap( ) ,
732- info_a
786+ . map( RangePatternInfo :: from)
787+ . as_ref( ) ,
788+ Some ( & info_a)
733789 ) ;
734790 assert_eq ! (
735791 pgd. get_date_pattern( DateGreatestDifferenceField :: Month )
736- . unwrap( ) ,
737- info_b
792+ . map( RangePatternInfo :: from)
793+ . as_ref( ) ,
794+ Some ( & info_b)
738795 ) ;
739796 assert_eq ! (
740797 pgd. get_date_pattern( DateGreatestDifferenceField :: Year )
741- . unwrap( ) ,
742- info_c
798+ . map( RangePatternInfo :: from)
799+ . as_ref( ) ,
800+ Some ( & info_c)
743801 ) ;
744802
745803 // 2. All identical -> dedup to 1 (at the largest field, Year)
@@ -756,21 +814,27 @@ mod try_from_patterns_tests {
756814 // Header value: 0b00010000 = 0x10
757815 assert_eq ! ( pgd. header. 0 , 0x10 ) ;
758816 assert_eq ! ( pgd. patterns. len( ) , 1 ) ;
817+
818+ let pgd_ule_box = zerovec:: ule:: encode_varule_to_box ( & pgd) ;
819+ let pgd: & PatternsByGreatestDifferenceULE = & pgd_ule_box;
759820 // Day and Month should fallback to Year (info_a)
760821 assert_eq ! (
761822 pgd. get_date_pattern( DateGreatestDifferenceField :: Day )
762- . unwrap( ) ,
763- info_a
823+ . map( RangePatternInfo :: from)
824+ . as_ref( ) ,
825+ Some ( & info_a)
764826 ) ;
765827 assert_eq ! (
766828 pgd. get_date_pattern( DateGreatestDifferenceField :: Month )
767- . unwrap( ) ,
768- info_a
829+ . map( RangePatternInfo :: from)
830+ . as_ref( ) ,
831+ Some ( & info_a)
769832 ) ;
770833 assert_eq ! (
771834 pgd. get_date_pattern( DateGreatestDifferenceField :: Year )
772- . unwrap( ) ,
773- info_a
835+ . map( RangePatternInfo :: from)
836+ . as_ref( ) ,
837+ Some ( & info_a)
774838 ) ;
775839
776840 // 3. Day and Month identical, Year different -> dedup Day to Month
@@ -787,21 +851,27 @@ mod try_from_patterns_tests {
787851 // Header value: 0b00010100 = 0x14
788852 assert_eq ! ( pgd. header. 0 , 0x14 ) ;
789853 assert_eq ! ( pgd. patterns. len( ) , 2 ) ;
854+
855+ let pgd_ule_box = zerovec:: ule:: encode_varule_to_box ( & pgd) ;
856+ let pgd: & PatternsByGreatestDifferenceULE = & pgd_ule_box;
790857 // Day should fallback to Month (info_a)
791858 assert_eq ! (
792859 pgd. get_date_pattern( DateGreatestDifferenceField :: Day )
793- . unwrap( ) ,
794- info_a
860+ . map( RangePatternInfo :: from)
861+ . as_ref( ) ,
862+ Some ( & info_a)
795863 ) ;
796864 assert_eq ! (
797865 pgd. get_date_pattern( DateGreatestDifferenceField :: Month )
798- . unwrap( ) ,
799- info_a
866+ . map( RangePatternInfo :: from)
867+ . as_ref( ) ,
868+ Some ( & info_a)
800869 ) ;
801870 assert_eq ! (
802871 pgd. get_date_pattern( DateGreatestDifferenceField :: Year )
803- . unwrap( ) ,
804- info_b
872+ . map( RangePatternInfo :: from)
873+ . as_ref( ) ,
874+ Some ( & info_b)
805875 ) ;
806876
807877 // 4. Day and Year identical, Month different -> no dedup (since Month is in between and different)
@@ -826,11 +896,11 @@ mod try_from_patterns_tests {
826896 assert_eq ! ( pgd. patterns. len( ) , 1 ) ;
827897
828898 // 6. Duplicate keys -> error
829- let input = vec ! [ ( 0 , info_a. clone( ) ) , ( 0 , info_b. clone ( ) ) ] ;
899+ let input = vec ! [ ( 0 , info_a. clone( ) ) , ( 0 , info_b) ] ;
830900 assert ! ( PatternsByGreatestDifference :: try_from_patterns( input) . is_err( ) ) ;
831901
832902 // 7. Out of bound keys -> error
833- let input = vec ! [ ( 4 , info_a. clone ( ) ) ] ;
903+ let input = vec ! [ ( 4 , info_a) ] ;
834904 assert ! ( PatternsByGreatestDifference :: try_from_patterns( input) . is_err( ) ) ;
835905 }
836906}
0 commit comments