@@ -34,7 +34,7 @@ impl fmt::Display for CFormatError {
34
34
use CFormatErrorType :: * ;
35
35
match self . typ {
36
36
UnmatchedKeyParentheses => write ! ( f, "incomplete format key" ) ,
37
- CFormatErrorType :: IncompleteFormat => write ! ( f, "incomplete format" ) ,
37
+ IncompleteFormat => write ! ( f, "incomplete format" ) ,
38
38
UnsupportedFormatChar ( c) => write ! (
39
39
f,
40
40
"unsupported format character '{}' ({:#x}) at index {}" ,
@@ -76,6 +76,18 @@ pub enum CFormatType {
76
76
String ( CFormatPreconversor ) ,
77
77
}
78
78
79
+ #[ derive( Debug , PartialEq ) ]
80
+ pub enum CFormatPrecision {
81
+ Quantity ( CFormatQuantity ) ,
82
+ Dot ,
83
+ }
84
+
85
+ impl From < CFormatQuantity > for CFormatPrecision {
86
+ fn from ( quantity : CFormatQuantity ) -> Self {
87
+ CFormatPrecision :: Quantity ( quantity)
88
+ }
89
+ }
90
+
79
91
bitflags ! {
80
92
pub struct CConversionFlags : u32 {
81
93
const ALTERNATE_FORM = 0b0000_0001 ;
@@ -110,7 +122,7 @@ pub struct CFormatSpec {
110
122
pub mapping_key : Option < String > ,
111
123
pub flags : CConversionFlags ,
112
124
pub min_field_width : Option < CFormatQuantity > ,
113
- pub precision : Option < CFormatQuantity > ,
125
+ pub precision : Option < CFormatPrecision > ,
114
126
pub format_type : CFormatType ,
115
127
pub format_char : char ,
116
128
// chars_consumed: usize,
@@ -143,10 +155,6 @@ impl CFormatSpec {
143
155
let precision = parse_precision ( iter) ?;
144
156
consume_length ( iter) ;
145
157
let ( format_type, format_char) = parse_format_type ( iter) ?;
146
- let precision = precision. or ( match format_type {
147
- CFormatType :: Float ( _) => Some ( CFormatQuantity :: Amount ( 6 ) ) ,
148
- _ => None ,
149
- } ) ;
150
158
151
159
Ok ( CFormatSpec {
152
160
mapping_key,
@@ -169,31 +177,22 @@ impl CFormatSpec {
169
177
string : String ,
170
178
fill_char : char ,
171
179
num_prefix_chars : Option < usize > ,
172
- fill_with_precision : bool ,
173
180
) -> String {
174
- let target_width = if fill_with_precision {
175
- & self . precision
176
- } else {
177
- & self . min_field_width
178
- } ;
179
181
let mut num_chars = string. chars ( ) . count ( ) ;
180
182
if let Some ( num_prefix_chars) = num_prefix_chars {
181
183
num_chars += num_prefix_chars;
182
184
}
183
185
let num_chars = num_chars;
184
186
185
- let width = match target_width {
187
+ let width = match & self . min_field_width {
186
188
Some ( CFormatQuantity :: Amount ( width) ) => cmp:: max ( width, & num_chars) ,
187
189
_ => & num_chars,
188
190
} ;
189
191
let fill_chars_needed = width. saturating_sub ( num_chars) ;
190
192
let fill_string = CFormatSpec :: compute_fill_string ( fill_char, fill_chars_needed) ;
191
193
192
194
if !fill_string. is_empty ( ) {
193
- // Don't left-adjust if precision-filling: that will always be prepending 0s to %d
194
- // arguments, the LEFT_ADJUST flag will be used by a later call to fill_string with
195
- // the 0-filled string as the string param.
196
- if !fill_with_precision && self . flags . contains ( CConversionFlags :: LEFT_ADJUST ) {
195
+ if self . flags . contains ( CConversionFlags :: LEFT_ADJUST ) {
197
196
format ! ( "{string}{fill_string}" )
198
197
} else {
199
198
format ! ( "{fill_string}{string}" )
@@ -203,19 +202,47 @@ impl CFormatSpec {
203
202
}
204
203
}
205
204
205
+ fn fill_string_with_precision ( & self , string : String , fill_char : char ) -> String {
206
+ let num_chars = string. chars ( ) . count ( ) ;
207
+
208
+ let width = match & self . precision {
209
+ Some ( CFormatPrecision :: Quantity ( CFormatQuantity :: Amount ( width) ) ) => {
210
+ cmp:: max ( width, & num_chars)
211
+ }
212
+ _ => & num_chars,
213
+ } ;
214
+ let fill_chars_needed = width. saturating_sub ( num_chars) ;
215
+ let fill_string = CFormatSpec :: compute_fill_string ( fill_char, fill_chars_needed) ;
216
+
217
+ if !fill_string. is_empty ( ) {
218
+ // Don't left-adjust if precision-filling: that will always be prepending 0s to %d
219
+ // arguments, the LEFT_ADJUST flag will be used by a later call to fill_string with
220
+ // the 0-filled string as the string param.
221
+ format ! ( "{fill_string}{string}" )
222
+ } else {
223
+ string
224
+ }
225
+ }
226
+
206
227
fn format_string_with_precision (
207
228
& self ,
208
229
string : String ,
209
- precision : Option < & CFormatQuantity > ,
230
+ precision : Option < & CFormatPrecision > ,
210
231
) -> String {
211
232
// truncate if needed
212
233
let string = match precision {
213
- Some ( CFormatQuantity :: Amount ( precision) ) if string. chars ( ) . count ( ) > * precision => {
234
+ Some ( CFormatPrecision :: Quantity ( CFormatQuantity :: Amount ( precision) ) )
235
+ if string. chars ( ) . count ( ) > * precision =>
236
+ {
214
237
string. chars ( ) . take ( * precision) . collect :: < String > ( )
215
238
}
239
+ Some ( CFormatPrecision :: Dot ) => {
240
+ // truncate to 0
241
+ String :: new ( )
242
+ }
216
243
_ => string,
217
244
} ;
218
- self . fill_string ( string, ' ' , None , false )
245
+ self . fill_string ( string, ' ' , None )
219
246
}
220
247
221
248
#[ inline]
@@ -225,11 +252,16 @@ impl CFormatSpec {
225
252
226
253
#[ inline]
227
254
pub fn format_char ( & self , ch : char ) -> String {
228
- self . format_string_with_precision ( ch. to_string ( ) , Some ( & CFormatQuantity :: Amount ( 1 ) ) )
255
+ self . format_string_with_precision (
256
+ ch. to_string ( ) ,
257
+ Some ( & ( CFormatQuantity :: Amount ( 1 ) . into ( ) ) ) ,
258
+ )
229
259
}
230
260
231
261
pub fn format_bytes ( & self , bytes : & [ u8 ] ) -> Vec < u8 > {
232
- let bytes = if let Some ( CFormatQuantity :: Amount ( precision) ) = self . precision {
262
+ let bytes = if let Some ( CFormatPrecision :: Quantity ( CFormatQuantity :: Amount ( precision) ) ) =
263
+ self . precision
264
+ {
233
265
& bytes[ ..cmp:: min ( bytes. len ( ) , precision) ]
234
266
} else {
235
267
bytes
@@ -282,7 +314,7 @@ impl CFormatSpec {
282
314
_ => self . flags . sign_string ( ) ,
283
315
} ;
284
316
285
- let padded_magnitude_string = self . fill_string ( magnitude_string, '0' , None , true ) ;
317
+ let padded_magnitude_string = self . fill_string_with_precision ( magnitude_string, '0' ) ;
286
318
287
319
if self . flags . contains ( CConversionFlags :: ZERO_PAD ) {
288
320
let fill_char = if !self . flags . contains ( CConversionFlags :: LEFT_ADJUST ) {
@@ -298,15 +330,13 @@ impl CFormatSpec {
298
330
padded_magnitude_string,
299
331
fill_char,
300
332
Some ( signed_prefix. chars( ) . count( ) ) ,
301
- false
302
333
) ,
303
334
)
304
335
} else {
305
336
self . fill_string (
306
337
format ! ( "{sign_string}{prefix}{padded_magnitude_string}" ) ,
307
338
' ' ,
308
339
None ,
309
- false ,
310
340
)
311
341
}
312
342
}
@@ -318,9 +348,13 @@ impl CFormatSpec {
318
348
self . flags . sign_string ( )
319
349
} ;
320
350
321
- let precision = match self . precision {
322
- Some ( CFormatQuantity :: Amount ( p) ) => p,
323
- _ => 6 ,
351
+ let precision = match & self . precision {
352
+ Some ( CFormatPrecision :: Quantity ( quantity) ) => match quantity {
353
+ CFormatQuantity :: Amount ( amount) => * amount,
354
+ CFormatQuantity :: FromValuesTuple => 6 ,
355
+ } ,
356
+ Some ( CFormatPrecision :: Dot ) => 0 ,
357
+ None => 6 ,
324
358
} ;
325
359
326
360
let magnitude_string = match & self . format_type {
@@ -381,11 +415,10 @@ impl CFormatSpec {
381
415
magnitude_string,
382
416
fill_char,
383
417
Some ( sign_string. chars( ) . count( ) ) ,
384
- false
385
418
)
386
419
)
387
420
} else {
388
- self . fill_string ( format ! ( "{sign_string}{magnitude_string}" ) , ' ' , None , false )
421
+ self . fill_string ( format ! ( "{sign_string}{magnitude_string}" ) , ' ' , None )
389
422
}
390
423
}
391
424
}
@@ -510,15 +543,19 @@ where
510
543
Ok ( None )
511
544
}
512
545
513
- fn parse_precision < T , I > ( iter : & mut ParseIter < I > ) -> Result < Option < CFormatQuantity > , ParsingError >
546
+ fn parse_precision < T , I > ( iter : & mut ParseIter < I > ) -> Result < Option < CFormatPrecision > , ParsingError >
514
547
where
515
548
T : Into < char > + Copy ,
516
549
I : Iterator < Item = T > ,
517
550
{
518
551
if let Some ( & ( _, c) ) = iter. peek ( ) {
519
552
if c. into ( ) == '.' {
520
553
iter. next ( ) . unwrap ( ) ;
521
- return parse_quantity ( iter) ;
554
+ return Ok ( Some (
555
+ parse_quantity ( iter) ?
556
+ . map ( CFormatPrecision :: Quantity )
557
+ . unwrap_or ( CFormatPrecision :: Dot ) ,
558
+ ) ) ;
522
559
}
523
560
}
524
561
Ok ( None )
@@ -848,6 +885,20 @@ mod tests {
848
885
. format_string( "Hello, World!" . to_owned( ) ) ,
849
886
"Hell " . to_owned( )
850
887
) ;
888
+ assert_eq ! (
889
+ "%.s"
890
+ . parse:: <CFormatSpec >( )
891
+ . unwrap( )
892
+ . format_string( "Hello, World!" . to_owned( ) ) ,
893
+ "" . to_owned( )
894
+ ) ;
895
+ assert_eq ! (
896
+ "%5.s"
897
+ . parse:: <CFormatSpec >( )
898
+ . unwrap( )
899
+ . format_string( "Hello, World!" . to_owned( ) ) ,
900
+ " " . to_owned( )
901
+ ) ;
851
902
}
852
903
853
904
#[ test]
@@ -863,13 +914,27 @@ mod tests {
863
914
864
915
#[ test]
865
916
fn test_parse_and_format_number ( ) {
917
+ assert_eq ! (
918
+ "%5d"
919
+ . parse:: <CFormatSpec >( )
920
+ . unwrap( )
921
+ . format_number( & BigInt :: from( 27 ) ) ,
922
+ " 27" . to_owned( )
923
+ ) ;
866
924
assert_eq ! (
867
925
"%05d"
868
926
. parse:: <CFormatSpec >( )
869
927
. unwrap( )
870
928
. format_number( & BigInt :: from( 27 ) ) ,
871
929
"00027" . to_owned( )
872
930
) ;
931
+ assert_eq ! (
932
+ "%.5d"
933
+ . parse:: <CFormatSpec >( )
934
+ . unwrap( )
935
+ . format_number( & BigInt :: from( 27 ) ) ,
936
+ "00027" . to_owned( )
937
+ ) ;
873
938
assert_eq ! (
874
939
"%+05d"
875
940
. parse:: <CFormatSpec >( )
@@ -927,6 +992,18 @@ mod tests {
927
992
"%f" . parse:: <CFormatSpec >( ) . unwrap( ) . format_float( 1.2345 ) ,
928
993
"1.234500"
929
994
) ;
995
+ assert_eq ! (
996
+ "%.2f" . parse:: <CFormatSpec >( ) . unwrap( ) . format_float( 1.2345 ) ,
997
+ "1.23"
998
+ ) ;
999
+ assert_eq ! (
1000
+ "%.f" . parse:: <CFormatSpec >( ) . unwrap( ) . format_float( 1.2345 ) ,
1001
+ "1"
1002
+ ) ;
1003
+ assert_eq ! (
1004
+ "%+.f" . parse:: <CFormatSpec >( ) . unwrap( ) . format_float( 1.2345 ) ,
1005
+ "+1"
1006
+ ) ;
930
1007
assert_eq ! (
931
1008
"%+f" . parse:: <CFormatSpec >( ) . unwrap( ) . format_float( 1.2345 ) ,
932
1009
"+1.234500"
0 commit comments