@@ -98,6 +98,7 @@ pub enum FormatType {
98
98
GeneralFormatUpper ,
99
99
FixedPointLower ,
100
100
FixedPointUpper ,
101
+ Percentage ,
101
102
}
102
103
103
104
#[ derive( Debug , PartialEq ) ]
@@ -232,11 +233,12 @@ fn parse_format_type(text: &str) -> (Option<FormatType>, &str) {
232
233
Some ( 'g' ) => ( Some ( FormatType :: GeneralFormatLower ) , chars. as_str ( ) ) ,
233
234
Some ( 'G' ) => ( Some ( FormatType :: GeneralFormatUpper ) , chars. as_str ( ) ) ,
234
235
Some ( 'n' ) => ( Some ( FormatType :: Number ) , chars. as_str ( ) ) ,
236
+ Some ( '%' ) => ( Some ( FormatType :: Percentage ) , chars. as_str ( ) ) ,
235
237
_ => ( None , text) ,
236
238
}
237
239
}
238
240
239
- fn parse_format_spec ( text : & str ) -> FormatSpec {
241
+ fn parse_format_spec ( text : & str ) -> Result < FormatSpec , & ' static str > {
240
242
let ( preconversor, after_preconversor) = parse_preconversor ( text) ;
241
243
let ( mut fill, mut align, after_align) = parse_fill_and_align ( after_preconversor) ;
242
244
let ( sign, after_sign) = parse_sign ( after_align) ;
@@ -245,14 +247,17 @@ fn parse_format_spec(text: &str) -> FormatSpec {
245
247
let ( width, after_width) = parse_number ( after_zero) ;
246
248
let ( grouping_option, after_grouping_option) = parse_grouping_option ( after_width) ;
247
249
let ( precision, after_precision) = parse_precision ( after_grouping_option) ;
248
- let ( format_type, _) = parse_format_type ( after_precision) ;
250
+ let ( format_type, after_format_type) = parse_format_type ( after_precision) ;
251
+ if !after_format_type. is_empty ( ) {
252
+ return Err ( "Invalid format spec" ) ;
253
+ }
249
254
250
255
if zero && fill. is_none ( ) {
251
256
fill. replace ( '0' ) ;
252
257
align = align. or ( Some ( FormatAlign :: AfterSign ) ) ;
253
258
}
254
259
255
- FormatSpec {
260
+ Ok ( FormatSpec {
256
261
preconversor,
257
262
fill,
258
263
align,
@@ -262,11 +267,11 @@ fn parse_format_spec(text: &str) -> FormatSpec {
262
267
grouping_option,
263
268
precision,
264
269
format_type,
265
- }
270
+ } )
266
271
}
267
272
268
273
impl FormatSpec {
269
- pub fn parse ( text : & str ) -> FormatSpec {
274
+ pub fn parse ( text : & str ) -> Result < FormatSpec , & ' static str > {
270
275
parse_format_spec ( text)
271
276
}
272
277
@@ -369,6 +374,11 @@ impl FormatSpec {
369
374
Some ( FormatType :: ExponentLower ) => {
370
375
Err ( "Format code 'e' for object of type 'float' not implemented yet" )
371
376
}
377
+ Some ( FormatType :: Percentage ) => match magnitude {
378
+ magnitude if magnitude. is_nan ( ) => Ok ( "nan%" . to_string ( ) ) ,
379
+ magnitude if magnitude. is_infinite ( ) => Ok ( "inf%" . to_string ( ) ) ,
380
+ _ => Ok ( format ! ( "{:.*}%" , precision, magnitude * 100.0 ) ) ,
381
+ } ,
372
382
None => {
373
383
match magnitude {
374
384
magnitude if magnitude. is_nan ( ) => Ok ( "nan" . to_string ( ) ) ,
@@ -443,6 +453,9 @@ impl FormatSpec {
443
453
_ => Err ( "Unable to convert int to float" ) ,
444
454
}
445
455
}
456
+ Some ( FormatType :: Percentage ) => {
457
+ Err ( "Format code '%' for object of type 'int' not implemented yet" )
458
+ }
446
459
None => Ok ( magnitude. to_str_radix ( 10 ) ) ,
447
460
} ;
448
461
if raw_magnitude_string_result. is_err ( ) {
@@ -525,7 +538,7 @@ pub enum FormatParseError {
525
538
impl FromStr for FormatSpec {
526
539
type Err = & ' static str ;
527
540
fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
528
- Ok ( FormatSpec :: parse ( s) )
541
+ FormatSpec :: parse ( s)
529
542
}
530
543
}
531
544
@@ -702,7 +715,7 @@ mod tests {
702
715
703
716
#[ test]
704
717
fn test_width_only ( ) {
705
- let expected = FormatSpec {
718
+ let expected = Ok ( FormatSpec {
706
719
preconversor : None ,
707
720
fill : None ,
708
721
align : None ,
@@ -712,13 +725,13 @@ mod tests {
712
725
grouping_option : None ,
713
726
precision : None ,
714
727
format_type : None ,
715
- } ;
728
+ } ) ;
716
729
assert_eq ! ( parse_format_spec( "33" ) , expected) ;
717
730
}
718
731
719
732
#[ test]
720
733
fn test_fill_and_width ( ) {
721
- let expected = FormatSpec {
734
+ let expected = Ok ( FormatSpec {
722
735
preconversor : None ,
723
736
fill : Some ( '<' ) ,
724
737
align : Some ( FormatAlign :: Right ) ,
@@ -728,13 +741,13 @@ mod tests {
728
741
grouping_option : None ,
729
742
precision : None ,
730
743
format_type : None ,
731
- } ;
744
+ } ) ;
732
745
assert_eq ! ( parse_format_spec( "<>33" ) , expected) ;
733
746
}
734
747
735
748
#[ test]
736
749
fn test_all ( ) {
737
- let expected = FormatSpec {
750
+ let expected = Ok ( FormatSpec {
738
751
preconversor : None ,
739
752
fill : Some ( '<' ) ,
740
753
align : Some ( FormatAlign :: Right ) ,
@@ -744,38 +757,52 @@ mod tests {
744
757
grouping_option : Some ( FormatGrouping :: Comma ) ,
745
758
precision : Some ( 11 ) ,
746
759
format_type : Some ( FormatType :: Binary ) ,
747
- } ;
760
+ } ) ;
748
761
assert_eq ! ( parse_format_spec( "<>-#23,.11b" ) , expected) ;
749
762
}
750
763
751
764
#[ test]
752
765
fn test_format_int ( ) {
753
766
assert_eq ! (
754
- parse_format_spec( "d" ) . format_int( & BigInt :: from_bytes_be( Sign :: Plus , b"\x10 " ) ) ,
767
+ parse_format_spec( "d" )
768
+ . unwrap( )
769
+ . format_int( & BigInt :: from_bytes_be( Sign :: Plus , b"\x10 " ) ) ,
755
770
Ok ( "16" . to_string( ) )
756
771
) ;
757
772
assert_eq ! (
758
- parse_format_spec( "x" ) . format_int( & BigInt :: from_bytes_be( Sign :: Plus , b"\x10 " ) ) ,
773
+ parse_format_spec( "x" )
774
+ . unwrap( )
775
+ . format_int( & BigInt :: from_bytes_be( Sign :: Plus , b"\x10 " ) ) ,
759
776
Ok ( "10" . to_string( ) )
760
777
) ;
761
778
assert_eq ! (
762
- parse_format_spec( "b" ) . format_int( & BigInt :: from_bytes_be( Sign :: Plus , b"\x10 " ) ) ,
779
+ parse_format_spec( "b" )
780
+ . unwrap( )
781
+ . format_int( & BigInt :: from_bytes_be( Sign :: Plus , b"\x10 " ) ) ,
763
782
Ok ( "10000" . to_string( ) )
764
783
) ;
765
784
assert_eq ! (
766
- parse_format_spec( "o" ) . format_int( & BigInt :: from_bytes_be( Sign :: Plus , b"\x10 " ) ) ,
785
+ parse_format_spec( "o" )
786
+ . unwrap( )
787
+ . format_int( & BigInt :: from_bytes_be( Sign :: Plus , b"\x10 " ) ) ,
767
788
Ok ( "20" . to_string( ) )
768
789
) ;
769
790
assert_eq ! (
770
- parse_format_spec( "+d" ) . format_int( & BigInt :: from_bytes_be( Sign :: Plus , b"\x10 " ) ) ,
791
+ parse_format_spec( "+d" )
792
+ . unwrap( )
793
+ . format_int( & BigInt :: from_bytes_be( Sign :: Plus , b"\x10 " ) ) ,
771
794
Ok ( "+16" . to_string( ) )
772
795
) ;
773
796
assert_eq ! (
774
- parse_format_spec( "^ 5d" ) . format_int( & BigInt :: from_bytes_be( Sign :: Minus , b"\x10 " ) ) ,
797
+ parse_format_spec( "^ 5d" )
798
+ . unwrap( )
799
+ . format_int( & BigInt :: from_bytes_be( Sign :: Minus , b"\x10 " ) ) ,
775
800
Ok ( " -16 " . to_string( ) )
776
801
) ;
777
802
assert_eq ! (
778
- parse_format_spec( "0>+#10x" ) . format_int( & BigInt :: from_bytes_be( Sign :: Plus , b"\x10 " ) ) ,
803
+ parse_format_spec( "0>+#10x" )
804
+ . unwrap( )
805
+ . format_int( & BigInt :: from_bytes_be( Sign :: Plus , b"\x10 " ) ) ,
779
806
Ok ( "00000+0x10" . to_string( ) )
780
807
) ;
781
808
}
0 commit comments