1
- use crate :: format:: { parse_number , parse_precision } ;
1
+ use crate :: format:: get_num_digits ;
2
2
/// Implementation of Printf-Style string formatting
3
3
/// [https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting]
4
4
use num_bigint:: { BigInt , Sign } ;
@@ -70,12 +70,18 @@ bitflags! {
70
70
}
71
71
}
72
72
73
+ #[ derive( Debug , PartialEq ) ]
74
+ pub enum CFormatQuantity {
75
+ Amount ( usize ) ,
76
+ FromValuesTuple ,
77
+ }
78
+
73
79
#[ derive( Debug , PartialEq ) ]
74
80
pub struct CFormatSpec {
75
81
pub mapping_key : Option < String > ,
76
82
pub flags : CConversionFlags ,
77
- pub min_field_width : Option < usize > ,
78
- pub precision : Option < usize > ,
83
+ pub min_field_width : Option < CFormatQuantity > ,
84
+ pub precision : Option < CFormatQuantity > ,
79
85
pub format_type : CFormatType ,
80
86
pub format_char : char ,
81
87
chars_consumed : usize ,
@@ -101,8 +107,8 @@ impl CFormatSpec {
101
107
let num_chars = num_chars;
102
108
103
109
let width = match self . min_field_width {
104
- Some ( width) => cmp:: max ( width, num_chars) ,
105
- None => num_chars,
110
+ Some ( CFormatQuantity :: Amount ( width) ) => cmp:: max ( width, num_chars) ,
111
+ _ => num_chars,
106
112
} ;
107
113
let fill_chars_needed = width - num_chars;
108
114
let fill_string = CFormatSpec :: compute_fill_string ( fill_char, fill_chars_needed) ;
@@ -121,7 +127,7 @@ impl CFormatSpec {
121
127
pub fn format_string ( & self , string : String ) -> String {
122
128
let mut string = string;
123
129
// truncate if needed
124
- if let Some ( precision) = self . precision {
130
+ if let Some ( CFormatQuantity :: Amount ( precision) ) = self . precision {
125
131
if string. len ( ) > precision {
126
132
string. truncate ( precision) ;
127
133
}
@@ -242,6 +248,32 @@ impl FromStr for CFormatString {
242
248
}
243
249
}
244
250
251
+ fn parse_quantity ( text : & str ) -> ( Option < CFormatQuantity > , & str ) {
252
+ let num_digits: usize = get_num_digits ( text) ;
253
+ if num_digits == 0 {
254
+ let mut chars = text. chars ( ) ;
255
+ return match chars. next ( ) {
256
+ Some ( '*' ) => ( Some ( CFormatQuantity :: FromValuesTuple ) , chars. as_str ( ) ) ,
257
+ _ => ( None , text) ,
258
+ } ;
259
+ }
260
+ // This should never fail
261
+ (
262
+ Some ( CFormatQuantity :: Amount (
263
+ text[ ..num_digits] . parse :: < usize > ( ) . unwrap ( ) ,
264
+ ) ) ,
265
+ & text[ num_digits..] ,
266
+ )
267
+ }
268
+
269
+ fn parse_precision ( text : & str ) -> ( Option < CFormatQuantity > , & str ) {
270
+ let mut chars = text. chars ( ) ;
271
+ match chars. next ( ) {
272
+ Some ( '.' ) => parse_quantity ( & chars. as_str ( ) ) ,
273
+ _ => ( None , text) ,
274
+ }
275
+ }
276
+
245
277
fn parse_literal_single ( text : & str ) -> Result < ( char , & str ) , CFormatErrorType > {
246
278
let mut chars = text. chars ( ) ;
247
279
// TODO get rid of the unwrap
@@ -445,7 +477,7 @@ impl FromStr for CFormatSpec {
445
477
let ( mapping_key, after_mapping_key) =
446
478
parse_spec_mapping_key ( chars. as_str ( ) ) . map_err ( |err| ( err, consumed) ) ?;
447
479
let ( flags, after_flags) = parse_flags ( after_mapping_key) ;
448
- let ( width, after_width) = parse_number ( after_flags) ;
480
+ let ( width, after_width) = parse_quantity ( after_flags) ;
449
481
let ( precision, after_precision) = parse_precision ( after_width) ;
450
482
// A length modifier (h, l, or L) may be present,
451
483
// but is ignored as it is not necessary for Python – so e.g. %ld is identical to %d.
@@ -459,7 +491,7 @@ impl FromStr for CFormatSpec {
459
491
let precision = match precision {
460
492
Some ( precision) => Some ( precision) ,
461
493
None => match format_type {
462
- CFormatType :: Float ( _) => Some ( 6 ) ,
494
+ CFormatType :: Float ( _) => Some ( CFormatQuantity :: Amount ( 6 ) ) ,
463
495
_ => None ,
464
496
} ,
465
497
} ;
@@ -575,7 +607,7 @@ mod tests {
575
607
format_type : CFormatType :: Number ( CNumberType :: Decimal ) ,
576
608
format_char : 'd' ,
577
609
chars_consumed : 17 ,
578
- min_field_width : Some ( 10 ) ,
610
+ min_field_width : Some ( CFormatQuantity :: Amount ( 10 ) ) ,
579
611
precision : None ,
580
612
mapping_key : None ,
581
613
flags : CConversionFlags :: all ( ) ,
0 commit comments